Namensräume
Varianten
Aktionen

if Anweisung

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Führt bedingt eine andere Anweisung aus.

Wird verwendet, wenn Code basierend auf einer Bedingung ausgeführt werden muss oder ob die if Anweisung in einem manifest konstant ausgewerteten Kontext ausgewertet wird(seit C++23).

Inhalt

[bearbeiten] 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)
1) if Anweisung ohne else Zweig
2) if Anweisung mit else Zweig
3) Consteval if Anweisung ohne else Zweig
4) Consteval if Anweisung mit else Zweig
attr - (seit C++11) eine beliebige Anzahl von Attributen
constexpr - (seit C++17) falls vorhanden, wird die Anweisung zu einer constexpr if Anweisung
init-statement - (seit C++17) entweder
(seit C++23)

Beachten Sie, dass jede init-statement mit einem Semikolon enden muss. Deshalb wird sie oft informell als Ausdruck oder Deklaration gefolgt von einem Semikolon beschrieben.

condition - eine Bedingung
statement-true - die Anweisung, die ausgeführt wird, wenn die condition true ergibt
statement-false - die Anweisung, die ausgeführt wird, wenn die condition false ergibt
compound-statement - die zusammengesetzte Anweisung, die ausgeführt wird, wenn die if Anweisung in einem manifest konstant ausgewerteten Kontext ausgewertet wird (oder nicht in einem solchen Kontext ausgewertet wird, wenn ! vor consteval steht)
Anweisung - die Anweisung (muss eine zusammengesetzte Anweisung sein, siehe unten), die ausgeführt wird, wenn die if Anweisung nicht in einem manifest konstant ausgewerteten Kontext ausgewertet wird (oder in einem solchen Kontext ausgewertet wird, wenn ! vor consteval steht)

[bearbeiten] Bedingung

Eine condition kann entweder ein Ausdruck oder eine einfache Deklaration sein.

(seit C++26)
  • Wenn sie syntaktisch als Ausdruck aufgelöst werden kann, wird sie als Ausdruck behandelt. Andernfalls wird sie als Deklaration behandelt, die keine strukturierte Bindungsdeklaration ist(seit C++26).

Wenn der Kontrollfluss auf die Bedingung trifft, liefert die Bedingung einen Wert, der verwendet wird, um zu bestimmen, zu welchem Zweig der Kontrollfluss geht.

[bearbeiten] Ausdruck

Wenn condition ein Ausdruck ist, ist der gelieferte Wert der Wert des Ausdrucks, der kontextuell zu bool konvertiert wird. Wenn diese Konvertierung fehlerhaft ist, ist das Programm fehlerhaft.

[bearbeiten] Deklaration

Wenn condition eine einfache Deklaration ist, ist der gelieferte Wert der Wert der Entscheidungsvariable (siehe unten), kontextuell zu bool konvertiert. Wenn diese Konvertierung fehlerhaft ist, ist das Programm fehlerhaft.

[bearbeiten] Nicht-strukturierte Bindungsdeklaration

Die Deklaration hat folgende Einschränkungen

  • Folgt syntaktisch der folgenden Form
  • type-specifier-seq declarator = assignment-expression
(bis C++11)
  • attribute-specifier-seq(optional) decl-specifier-seq declarator brace-or-equal-initializer
(seit C++11)

Die Entscheidungsvariable der Deklaration ist die deklarierte Variable.

Strukturierte Bindungsdeklaration

Die Deklaration hat folgende Einschränkungen

Die Entscheidungsvariable der Deklaration ist die erfundene Variable e, die durch die Deklaration eingeführt wird.

(seit C++26)

[bearbeiten] Zweigwahl

Wenn die condition true ergibt, wird statement-true ausgeführt.

Wenn der else Teil der if Anweisung vorhanden ist und die condition false ergibt, wird statement-false 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 verschachtelten if Anweisungen wird das else mit dem nächstgelegenen if assoziiert, das noch kein assoziiertes else hat).

#include <iostream>
 
int main()
{
    // simple if-statement with an else clause
    int i = 2;
    if (i > 2)
        std::cout << i << " is greater than 2\n";
    else
        std::cout << i << " is not greater than 2\n";
 
    // nested if-statement
    int j = 1;
    if (i > 1)
        if (j > 2)
            std::cout << i << " > 1 and " << j << " > 2\n";
        else // this else is part of if (j > 2), not of if (i > 1)
            std::cout << i << " > 1 and " << j << " <= 2\n";
 
    // declarations can be used as conditions with dynamic_cast
    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 fails, returns nullptr
        p->df(); // not executed
 
    if (auto p = dynamic_cast<Derived*>(bp2)) // cast succeeds
        p->df(); // executed
}

Ausgabe

2 is not greater than 2
2 > 1 and 1 <= 2
df()

if Anweisungen mit Initialisierer

Wenn init-statement verwendet wird, ist die if Anweisung äquivalent zu

{
init-statement
attr (optional) if constexpr(optional) ( condition )
statement-true

}

or

{
init-statement
attr (optional) if constexpr(optional) ( condition )
statement-true
else
statement-false

}

Mit der Ausnahme, dass Namen, die durch die init-statement deklariert wurden (wenn init-statement eine Deklaration ist) und Namen, die durch die condition deklariert wurden (wenn condition eine Deklaration ist), sich im selben Gültigkeitsbereich befinden, der auch der Gültigkeitsbereich beider statement s 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 if

Die 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 konvertierter konstanter Ausdruck vom Typ bool sein(bis C++23)ein Ausdruck, der kontextuell zu bool konvertiert wird, wobei die Konvertierung ein konstanter Ausdruck ist(seit C++23).

Wenn condition true ergibt, wird statement-false verworfen (falls vorhanden), andernfalls wird statement-true verworfen.

Die return Anweisungen in einer verworfenen Anweisung nehmen nicht an der Rückgabetyperkennung der Funktion teil.

template<typename T>
auto get_value(T t)
{
    if constexpr (std::is_pointer_v<T>)
        return *t; // deduces return type to int for T = int*
    else
        return t;  // deduces return type to int for T = int
}

Die verworfene Anweisung kann eine Variable ODR-verwenden, die nicht definiert ist.

extern int x; // no definition of x required
 
int f()
{
    if constexpr (true)
        return 0;
    else if (x)
        return x;
    else
        return -x;
}

Außerhalb einer Vorlage wird eine verworfene 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; // Error even though in discarded statement
    }
}

Wenn eine constexpr if Anweisung innerhalb einer Vorlageneinheit erscheint und wenn condition nach der Instanziierung nicht wertabhängig ist, wird die verworfene Anweisung nicht instanziiert, wenn die umschließende Vorlage instanziiert wird.

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs)
{
    // ... handle p
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // never instantiated with an empty argument list
}

Die Bedingung bleibt wertabhängig nach der Instanziierung ist eine verschachtelte Vorlage.

template<class T>
void g()
{
    auto lm = [=](auto p)
    {
        if constexpr (sizeof(T) == 1 && sizeof p == 1)
        {
            // this condition remains value-dependent after instantiation of g<T>,
            // which affects implicit lambda captures
            // this compound statement may be discarded only after
            // instantiation of the lambda body
        }
    };
}

Die verworfene Anweisung darf 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]; // ill-formed: invalid for every T
        static_assert(false, "Must be arithmetic"); // ill-formed before CWG2518
    }
}

Der übliche Workaround vor der Implementierung von CWG Issue 2518 für eine solche Catch-all-Anweisung ist ein typenabhä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 before CWG2518
        static_assert(dependent_false_v<T>, "Must be arithmetic");
    }
}

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 if

Die Anweisung, die mit if consteval beginnt, wird als *consteval if Anweisung* bezeichnet. Alle Unteranweisungen einer consteval if Anweisung sind kontrollflussbeschränkte Anweisungen.

statement muss eine zusammengesetzte Anweisung sein, und sie wird immer noch als Teil der consteval if Anweisung behandelt, auch wenn sie keine zusammengesetzte Anweisung ist (und somit zu einem Kompilierungsfehler führt).

constexpr void f(bool b)
{
    if (true)
        if consteval {}
        else ; // error: not a compound-statement
               // else not associated with outer if
}

Wenn eine consteval if Anweisung in einem manifest konstant ausgewerteten Kontext ausgewertet wird, wird compound-statement ausgeführt. Andernfalls wird statement ausgeführt, wenn es vorhanden ist.

Wenn die Anweisung mit if !consteval beginnt, müssen compound-statement und statement (falls vorhanden) beide zusammengesetzte Anweisungen sein. Solche Anweisungen werden nicht als consteval if Anweisungen betrachtet, sind aber äquivalent zu consteval if Anweisungen.

  • if !consteval {/* stmt */ } ist äquivalent zu
if consteval {} else {/* stmt */}.
  • if !consteval {/* stmt-1 */} else {/* stmt-2 */} ist äquivalent zu
if consteval {/* stmt-2 */} else {/* stmt-1 */}.

compound-statement in einer consteval if Anweisung (oder statement in der negativen Form) befindet sich in einem sofortigen Funktionskontext, in dem ein Aufruf einer sofortigen Funktion keine konstante Anweisung sein muss.

#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 // use a compile-time friendly algorithm
    {
        return ipow_ct(base, exp);
    }
    else // use runtime evaluation
    {
        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)

[bearbeiten] Hinweise

Wenn statement-true oder statement-false keine zusammengesetzte Anweisung ist, wird sie behandelt, als wäre sie

if (x)
    int i;
// i is no longer in scope

ist dasselbe wie

if (x)
{
    int i;
}
// i is no longer in scope

Der Gültigkeitsbereich des Namens, der von condition eingeführt wird, falls es sich um eine Deklaration handelt, ist der kombinierte Gültigkeitsbereich der Körper beider Anweisungen.

if (int x = f())
{
    int x; // error: redeclaration of x
}
else
{
    int x; // error: redeclaration of x
}

Wenn statement-true durch goto oder longjmp erreicht wird, wird condition nicht ausgewertet und statement-false nicht ausgeführt.

Integrierte Konvertierungen sind in der condition einer constexpr if Anweisung nicht erlaubt, außer für nicht-verengende Ganzzahlkonvertierungen zu bool.

(seit C++17)
(bis C++23)
Feature-Testmakro Wert Std Feature
__cpp_if_constexpr 201606L (C++17) constexpr if
__cpp_if_consteval 202106L (C++23) consteval if

[bearbeiten] Schlüsselwörter

if, else, constexpr, consteval

[bearbeiten] 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 ein Label erreicht wird
die Bedingung nicht ausgewertet und die zweite
Unteranweisung nicht ausgeführt wird (wie in C)

[bearbeiten] Siehe auch

erkennt, ob der Aufruf innerhalb eines konstant ausgewerteten Kontexts erfolgt
(Funktion) [bearbeiten]
C-Dokumentation für if Anweisung