if
statement
Führt bedingt eine weitere Anweisung aus.
Wird verwendet, wenn Code basierend auf einer Bedingung ausgeführt werden muss , oder ob die if -Anweisung in einem offensichtlich konstant ausgewerteten Kontext evaluiert wird (since C++23) .
Inhaltsverzeichnis |
Syntax
attr
(optional)
if
constexpr
(optional)
(
init-statement
(optional)
condition
)
statement-true
|
(1) | ||||||||
attr
(optional)
if
constexpr
(optional)
(
init-statement
(optional)
condition
)
statement-true
else
statement-false
|
(2) | ||||||||
attr
(optional)
if
!
(optional)
consteval
compound-statement
|
(3) | (seit C++23) | |||||||
attr
(optional)
if
!
(optional)
consteval
compound-statement
else
statement
|
(4) | (seit C++23) | |||||||
| attr | - | (seit C++11) beliebig viele Attribute | ||
constexpr
|
- | (seit C++17) falls vorhanden, wird die Anweisung zu einer constexpr-if-Anweisung | ||
| init-statement | - |
(seit C++17)
entweder
Beachten Sie, dass jede init-statement mit einem Semikolon enden muss. Deshalb wird sie informell oft als Ausdruck oder Deklaration gefolgt von einem Semikolon beschrieben. |
||
| condition | - | eine Bedingung | ||
| statement-true | - | die Anweisung , die ausgeführt wird, falls condition zu true ausgewertet wird | ||
| statement-false | - | die Anweisung, die ausgeführt wird, falls condition zu false ausgewertet wird | ||
| compound-statement | - |
die
Verbundanweisung
, die ausgeführt wird, wenn die
if
-Anweisung in einem
offensichtlich konstant ausgewerteten Kontext
ausgewertet wird (oder nicht in einem solchen Kontext ausgewertet wird, falls
!
vor
consteval
steht)
|
||
| statement | - |
die Anweisung (muss eine Verbundanweisung sein, siehe
unten
), die ausgeführt wird, wenn die
if
-Anweisung nicht in einem offensichtlich konstant ausgewerteten Kontext ausgewertet wird (oder in einem solchen Kontext ausgewertet wird, falls
!
vor
consteval
steht)
|
Bedingung
Eine Bedingung kann entweder ein Ausdruck oder eine einfache Deklaration sein.
|
(since C++26) |
- Wenn es syntaktisch als Ausdruck aufgelöst werden kann, wird es als Ausdruck behandelt. Andernfalls wird es als Deklaration behandelt die keine strukturierte Bindungsdeklaration ist (seit C++26) .
Wenn die Steuerung die Bedingung erreicht, ergibt die Bedingung einen Wert, der verwendet wird, um zu bestimmen, welchen Zweig die Steuerung einschlagen wird.
Ausdruck
Wenn condition ein Ausdruck ist, ist der von ihm gelieferte Wert der Wert des Ausdrucks, der kontextuell zu bool konvertiert wird. Wenn diese Konvertierung fehlerhaft ist, ist das Programm fehlerhaft.
Deklaration
Wenn condition eine einfache Deklaration ist, ist der von ihr gelieferte Wert der Wert der Entscheidungsvariablen (siehe unten), kontextuell konvertiert zu bool . Wenn diese Konvertierung fehlerhaft ist, ist das Programm fehlerhaft.
Nicht-strukturierte Bindungsdeklaration
Die Deklaration unterliegt folgenden Einschränkungen:
- Syntaktisch entspricht es der folgenden Form:
|
(bis C++11) |
|
(seit C++11) |
- Der Deklarator darf keinen function oder ein array spezifizieren.
- Die type specifier sequence (bis C++11) declaration specifier sequence darf nur Typspezifizierer und constexpr enthalten, und sie (seit C++11) darf keine class oder enumeration definieren.
Die Entscheidungsvariable der Deklaration ist die deklarierte Variable.
Strukturierte BindungsdeklarationDie Deklaration unterliegt folgenden Einschränkungen:
Die Entscheidungsvariable der Deklaration ist die eingeführte Variable e , die durch die Deklaration eingeführt wird . |
(seit C++26) |
Zweigauswahl
Wenn die Bedingung zu true ausgewertet wird, wird statement-true ausgeführt.
Wenn der else -Teil der if -Anweisung vorhanden ist und die Bedingung false liefert, wird Anweisung-falsch ausgeführt.
Wenn der else -Teil der if -Anweisung vorhanden ist und statement-true ebenfalls eine if -Anweisung ist, dann muss diese innere if -Anweisung ebenfalls einen else -Teil enthalten (mit anderen Worten: In geschachtelten if -Anweisungen wird else dem nächsten if zugeordnet, das noch keinen zugehörigen else -Teil besitzt).
#include <iostream> int main() { // einfache if-Anweisung mit else-Zweig int i = 2; if (i > 2) std::cout << i << " is greater than 2\n"; else std::cout << i << " is not greater than 2\n"; // verschachtelte if-Anweisung int j = 1; if (i > 1) if (j > 2) std::cout << i << " > 1 and " << j << " > 2\n"; else // dieses else gehört zu if (j > 2), nicht zu if (i > 1) std::cout << i << " > 1 and " << j << " <= 2\n"; // Deklarationen können als Bedingungen mit dynamic_cast verwendet werden struct Base { virtual ~Base() {} }; struct Derived : Base { void df() { std::cout << "df()\n"; } }; Base* bp1 = new Base; Base* bp2 = new Derived; if (Derived* p = dynamic_cast<Derived*>(bp1)) // Cast schlägt fehl, gibt nullptr zurück p->df(); // nicht ausgeführt if (auto p = dynamic_cast<Derived*>(bp2)) // Cast erfolgreich p->df(); // ausgeführt }
Ausgabe:
2 is not greater than 2 2 > 1 and 1 <= 2 df()
if Anweisungen mit InitialisiererWenn ein Init-Anweisung verwendet wird, entspricht die if -Anweisung
oder
Mit der Ausnahme, dass Namen, die durch die Init-Anweisung deklariert werden (falls Init-Anweisung eine Deklaration ist) und Namen, die durch Bedingung deklariert werden (falls Bedingung eine Deklaration ist), sich im selben Gültigkeitsbereich befinden, der auch der Gültigkeitsbereich beider Anweisungen ist. std::map<int, std::string> m; std::mutex mx; extern bool shared_flag; // guarded by mx int demo() { if (auto it = m.find(10); it != m.end()) return it->second.size(); if (char buf[10]; std::fgets(buf, 10, stdin)) m[0] += buf; if (std::lock_guard lock(mx); shared_flag) { unsafe_ping(); shared_flag = false; } if (int s; int count = ReadBytesWithSignal(&s)) { publish(count); raise(s); } if (const auto keywords = {"if", "for", "while"}; std::ranges::any_of(keywords, [&tok](const char* kw) { return tok == kw; })) { std::cerr << "Token must not be a keyword\n"; } } |
(seit C++17) | ||||||||||||||||||||||||||||||||||||||||||||||
Constexpr ifDie Anweisung, die mit if constexpr beginnt, wird als constexpr if-Anweisung bezeichnet. Alle Unteranweisungen einer constexpr if-Anweisung sind kontrollflussbeschränkte Anweisungen . In einer constexpr-if-Anweisung muss condition ein kontextuell umgewandelter konstanter Ausdruck vom Typ bool sein (bis C++23) ein Ausdruck sein, der kontextuell zu bool umgewandelt wird , wobei die Umwandlung ein konstanter Ausdruck ist (seit C++23) . Wenn condition zu true ausgewertet wird, dann wird statement-false verworfen (falls vorhanden), andernfalls wird statement-true verworfen. Die return -Anweisungen in einer verworfenen Anweisung nehmen nicht an der Ableitung des Funktionrückgabetyps teil: template<typename T> auto get_value(T t) { if constexpr (std::is_pointer_v<T>) return *t; // leitet Rückgabetyp zu int für T = int* ab else return t; // leitet Rückgabetyp zu int für T = int ab } Der verworfenen Anweisung kann ODR-use eine Variable verwenden, die nicht definiert ist: extern int x; // keine Definition von x erforderlich int f() { if constexpr (true) return 0; else if (x) return x; else return -x; } Außerhalb einer Vorlage wird eine verworfenen Anweisung vollständig geprüft. if constexpr ist kein Ersatz für die #if Präprozessor-Direktive: void f() { if constexpr(false) { int i = 0; int *p = i; // Fehler selbst in verworfenem Statement } } Wenn eine constexpr-if-Anweisung innerhalb einer templated entity erscheint und die condition nach der Instanziierung nicht value-dependent ist, wird die verworfenen Anweisung nicht instanziiert, wenn das umschließende Template instanziiert wird. template<typename T, typename ... Rest> void g(T&& p, Rest&& ...rs) { // ... p verarbeiten if constexpr (sizeof...(rs) > 0) g(rs...); // niemals mit einer leeren Argumentliste instanziiert } Die Bedingung bleibt wertabhängig nach der Instanziierung ist eine geschachtelte Vorlage: template<class T> void g() { auto lm = [=](auto p) { if constexpr (sizeof(T) == 1 && sizeof p == 1) { // diese Bedingung bleibt wertabhängig nach der Instanziierung von g<T>, // was implizite Lambda-Captures beeinflusst // dieser Verbundblock kann erst nach der // Instanziierung des Lambda-Rumpfes verworfen werden } }; } Der verworfenen Anweisung kann nicht für jede mögliche Spezialisierung fehlerhaft sein: template<typename T> void f() { if constexpr (std::is_arithmetic_v<T>) // ... else { using invalid_array = int[-1]; // ungültig: für jedes T ungültig static_assert(false, "Must be arithmetic"); // ungültig vor CWG2518 } } Die gängige Problemumgehung vor der Implementierung von CWG issue 2518 für eine solche Catch-all-Anweisung ist ein typabhängiger Ausdruck, der immer false ist: template<typename> constexpr bool dependent_false_v = false; template<typename T> void f() { if constexpr (std::is_arithmetic_v<T>) // ... else { // Workaround vor CWG2518 static_assert(dependent_false_v<T>, "Muss arithmetisch sein"); } } Eine typedef-Deklaration oder Alias-Deklaration (seit C++23) kann als Init-Statement einer constexpr-if-Anweisung verwendet werden, um den Gültigkeitsbereich des Typ-Alias zu reduzieren.
|
(seit C++17) |
Consteval ifDie Anweisung, die mit if consteval beginnt, wird als consteval-if-Anweisung bezeichnet. Alle Unteranweisungen einer consteval-if-Anweisung sind kontrollflussbeschränkte Anweisungen . statement muss ein zusammengesetzter Ausdruck sein, und es wird weiterhin als Teil der consteval-if-Anweisung behandelt, selbst wenn es kein zusammengesetzter Ausdruck ist (und somit zu einem Kompilierungsfehler führt):
Diesen Code ausführen
constexpr void f(bool b) { if (true) if consteval {} else ; // Fehler: keine Verbundanweisung // else nicht mit äußerem if assoziiert } Wenn eine consteval-if-Anweisung in einem manifestly constant-evaluated context ausgewertet wird, wird compound-statement ausgeführt. Andernfalls wird statement ausgeführt, falls vorhanden. Wenn die Anweisung mit if ! consteval beginnt, müssen sowohl die compound-statement als auch die statement (falls vorhanden) zusammengesetzte Anweisungen sein. Solche Anweisungen gelten nicht als consteval if-Anweisungen, sind jedoch äquivalent zu consteval if-Anweisungen:
compound-statement in einer consteval if-Anweisung (oder statement in der negativen Form) befindet sich in einem immediate function context , in welchem ein Aufruf einer immediate function keine konstante Expression sein muss.
Diesen Code ausführen
#include <cmath> #include <cstdint> #include <cstring> #include <iostream> constexpr bool is_constant_evaluated() noexcept { if consteval { return true; } else { return false; } } constexpr bool is_runtime_evaluated() noexcept { if not consteval { return true; } else { return false; } } consteval std::uint64_t ipow_ct(std::uint64_t base, std::uint8_t exp) { if (!base) return base; std::uint64_t res{1}; while (exp) { if (exp & 1) res *= base; exp /= 2; base *= base; } return res; } constexpr std::uint64_t ipow(std::uint64_t base, std::uint8_t exp) { if consteval // verwende einen kompilierzeitfreundlichen Algorithmus { return ipow_ct(base, exp); } else // verwende Laufzeitauswertung { return std::pow(base, exp); } } int main(int, const char* argv[]) { static_assert(ipow(0, 10) == 0 && ipow(2, 10) == 1024); std::cout << ipow(std::strlen(argv[0]), 3) << '\n'; } |
(seit C++23) |
Hinweise
Wenn statement-true oder statement-false keine zusammengesetzte Anweisung ist, wird sie so behandelt, als ob sie es wäre:
if (x) int i; // i ist nicht mehr im Gültigkeitsbereich
ist dasselbe wie
if (x) { int i; } // i ist nicht mehr im Gültigkeitsbereich
Der Gültigkeitsbereich des Namens, der durch die condition eingeführt wird, falls es sich um eine Deklaration handelt, ist der kombinierte Gültigkeitsbereich beider Anweisungskörper:
if (int x = f()) { int x; // Fehler: Neudeklaration von x } else { int x; // Fehler: Neudeklaration von x }
Wenn
statement-true
durch
goto
oder
longjmp
betreten wird,
wird
condition
nicht ausgewertet und
statement-false
nicht ausgeführt.
|
Eingebaute Konvertierungen sind in der Bedingung einer constexpr-if-Anweisung nicht erlaubt, außer nicht- einschränkenden integralen Konvertierungen zu bool . |
(seit C++17)
(bis C++23) |
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_if_constexpr
|
201606L
|
(C++17) |
constexpr
if
|
__cpp_if_consteval
|
202106L
|
(C++23) |
consteval
if
|
Schlüsselwörter
if , else , constexpr , consteval
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 631 | C++98 |
der Kontrollfluss war nicht spezifiziert, wenn die
erste Unteranweisung über eine Marke erreicht wird |
die Bedingung wird nicht ausgewertet und die zweite
Unteranweisung wird nicht ausgeführt (wie in C) |
Siehe auch
|
(C++20)
|
erkennt, ob der Aufruf in einem konstant ausgewerteten Kontext erfolgt
(Funktion) |
|
C-Dokumentation
für
if
-Anweisung
|
|