Namespaces
Variants

Constant expressions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Definiert einen Ausdruck , der zur Kompilierzeit ausgewertet werden kann.

Solche Ausdrücke können als konstante Template-Argumente, Array-Größen und in anderen Kontexten verwendet werden, die konstante Ausdrücke erfordern, z.B.

int n = 1;
std::array<int, n> a1;  // Fehler: „n“ ist kein konstanter Ausdruck
const int cn = 2;
std::array<int, cn> a2; // OK: „cn“ ist ein konstanter Ausdruck

Inhaltsverzeichnis

Definition

Ein Ausdruck, der zu einer der unten aufgeführten Kategorien für konstante Ausdrücke gehört, ist ein konstanter Ausdruck .

C++98 Kategorien für konstante Ausdrücke

Integraler konstanter Ausdruck (C++98)

An den folgenden Stellen erfordert C++ Ausdrücke, die zu einem integralen oder Aufzählungskonstanten ausgewertet werden:

Ein Ausdruck, der alle folgenden Bedingungen erfüllt, ist ein integraler konstanter Ausdruck :

  • Er bezieht nur die folgenden Entitäten ein:
  • Literale von arithmetischen Typen
  • Enumeratoren
  • Variablen oder statische Datenelemente, die alle folgenden Bedingungen erfüllen:
  • Sie sind const-qualifiziert.
  • Sie sind nicht volatile-qualifiziert.
  • Sie sind von integralem oder Aufzählungstyp.
  • Sie sind mit konstanten Ausdrücken initialisiert.
  • Er verwendet keine Gleitkomma-Literale, es sei denn, sie werden explizit konvertiert zu integralen oder Aufzählungstypen.
  • Er wendet keine Konvertierungen auf nicht-integralen und nicht-Aufzählungstypen an.
  • Er verwendet keine der folgenden Entitäten außer in den Operanden von sizeof :
  • Funktion
  • Klassenobjekt
  • Zeiger
  • Referenz
  • Zuweisungsoperator
  • Inkrementoperator
  • Dekrementoperator
  • Funktionsaufrufoperator
  • Kommaoperator

Andere Kategorien für konstante Ausdrücke

Andere Ausdrücke werden nur für den Zweck der konstanten Initialisierung als konstante Ausdrücke betrachtet. Ein solcher konstanter Ausdruck muss einer der folgenden Ausdrücke sein:

  • ein Ausdruck, der zu einem Nullzeigerwert ausgewertet wird
  • ein Ausdruck, der zu einem Null-Zeiger-auf-Mitglied-Wert ausgewertet wird
  • ein arithmetischer konstanter Ausdruck
  • ein Adresskonstanter Ausdruck
  • ein Referenzkonstanter Ausdruck
  • ein Adresskonstanter Ausdruck für einen vollständigen Objekttyp, plus oder minus einem integralen konstanten Ausdruck
  • ein Zeiger-auf-Mitglied konstanter Ausdruck

Ein arithmetischer konstanter Ausdruck ist ein Ausdruck, der die Anforderungen für einen integralen konstanten Ausdruck erfüllt, mit folgenden Ausnahmen:

  • Gleitkomma-Literale können ohne explizite Konvertierung verwendet werden.
  • Konvertierungen zu Gleitkommatypen können angewendet werden.

Ein Adresskonstanter Ausdruck ist ein Ausdruck von Zeigertyp, der alle folgenden Bedingungen erfüllt:

  • explizite Verwendung des Adressoperators
  • implizite Verwendung eines konstanten Template-Parameters von Zeigertyp
  • Verwendung eines Ausdrucks von Array- oder Funktionstyp
  • Der Ausdruck ruft keine Funktion auf.
  • Der Ausdruck verwendet explizite Zeigerkonvertierungen (außer dynamic_cast ) und die folgenden Operatoren ohne Zugriff auf das Ergebnisobjekt:
  • Indexoperator
  • Dereferenzierungsoperator
  • Adressoperator
  • Elementzugriffsoperator
  • Wenn der Indexoperator verwendet wird, ist einer seiner Operanden ein integraler konstanter Ausdruck.

Ein Referenzkonstanter Ausdruck ist ein Ausdruck von Referenztyp, der alle folgenden Bedingungen erfüllt:

  • Die Referenz bezeichnet ein Objekt mit statischer Speicherdauer, einen konstanten Template-Parameter von Referenztyp oder eine Funktion. Die Referenz bezeichnet kein Mitglied oder Basisklasse von nicht-POD-Klasse Typ.
  • Der Ausdruck ruft keine Funktion auf.
  • Der Ausdruck verwendet explizite Referenzkonvertierungen (außer dynamic_cast ) und die folgenden Operatoren ohne Zugriff auf das Ergebnisobjekt:
  • Indexoperator
  • Dereferenzierungsoperator
  • Adressoperator
  • Elementzugriffsoperator
  • Wenn der Indexoperator verwendet wird, ist einer seiner Operanden ein integraler konstanter Ausdruck.

Ein Zeiger-auf-Mitglied konstanter Ausdruck ist ein Ausdruck von Zeiger-auf-Mitglied-Typ, bei dem der Zeiger durch Anwendung des Adressoperators auf einen qualifizierten Bezeichner erstellt wird, optional vorangestellt von einer expliziten Zeiger-auf-Mitglied-Konvertierung.

(bis C++11)

Die folgenden Ausdrücke werden zusammen als konstante Ausdrücke  bezeichnet:

  • die Adresse eines Objekts mit statischer Speicherdauer
  • die Adresse einer Funktion
  • ein Nullzeigerwert
(seit C++11)
(bis C++14)

Folgende Entitäten sind zulässige Ergebnisse eines konstanten Ausdrucks :

  • Temporäre Objekte mit static storage duration
  • Nicht-temporäre Objekte mit static storage duration, deren Werte die nachfolgend aufgeführten Einschränkungen erfüllen
  • Nicht- immediate (since C++20) Funktionen

Ein konstanter Ausdruck ist entweder ein glvalue core constant expression , der auf eine Entität verweist, die ein zulässiges Ergebnis eines konstanten Ausdrucks ist, oder ein prvalue core constant expression, dessen Wert die folgenden Einschränkungen erfüllt:

  • Wenn der Wert ein Objekt vom Klassentyp ist, verweist jedes nicht-statische Datenelement vom Referenztyp auf eine Entität, die ein zulässiges Ergebnis eines konstanten Ausdrucks ist.
  • Wenn der Wert ein Objekt vom scalar type ist, hat es keinen indeterminate Wert.
  • Wenn der Wert vom pointer type ist, ist es einer der folgenden Werte:
  • die Adresse eines Objekts mit static storage duration
  • die Adresse hinter dem Ende eines Objekts mit static storage duration
  • die Adresse einer non-immediate (since C++20) Funktion
  • ein null pointer value
  • Wenn der Wert vom pointer-to-member-function type ist, bezeichnet er keine immediate function.
(since C++20)
  • Wenn der Wert ein Objekt vom Klassen- oder Arraytyp ist, erfüllt jedes Teilobjekt diese Einschränkungen für den Wert.
(since C++14)
(until C++26)

Ein konstanter Ausdruck ist entweder ein Glvalue- Core-Konstantausdruck , der auf ein Objekt oder eine Nicht- Immediate-Funktion verweist, oder ein Prvalue-Core-Konstantausdruck, dessen Wert die folgenden Einschränkungen erfüllt:

(seit C++26)

Bei der Bestimmung, ob ein Ausdruck ein konstanter Ausdruck ist, wird angenommen, dass Copy Elision nicht durchgeführt wird.

Die Definition von konstanten Ausdrücken in C++98 befindet sich vollständig innerhalb der Ausklappbox. Die folgende Beschreibung gilt für C++11 und spätere C++-Versionen.

Literaltyp

Die folgenden Typen werden zusammenfassend als literal types bezeichnet:

  • möglicherweise cv-qualifiziertes void
  • Skalartyp
  • Referenztyp
  • ein Array von Literaltyp
  • möglicherweise cv-qualifizierter Klassentyp, der alle folgenden Bedingungen erfüllt:
  • Es besitzt einen trivialen Destruktor (bis C++20) constexpr Destruktor (seit C++20) .
  • Alle seine nicht-statischen nicht-varianten Datenelemente und Basisklassen sind von nicht-flüchtigen Literaltypen.
  • Es ist einer der folgenden Typen:
(seit C++17)
  • ein Aggregat -Union-Typ, der eine der folgenden Bedingungen erfüllt:
  • Er hat kein Varianten-Mitglied .
  • Er hat mindestens ein Varianten-Mitglied von nicht-flüchtigem Literaltyp.
  • ein Nicht-Union-Aggregat-Typ, bei dem jedes seiner anonymen Union -Mitglieder eine der folgenden Bedingungen erfüllt:
  • Es hat kein Varianten-Mitglied.
  • Es hat mindestens ein Varianten-Mitglied von nicht-flüchtigem Literaltyp.
  • ein Typ mit mindestens einem constexpr -Konstruktor (Template), der kein Kopier- oder Verschiebungskonstruktor ist

Nur Objekte von Literaltypen können innerhalb eines konstanten Ausdrucks erstellt werden.

Kernkonstanter Ausdruck

Ein Kernkonstanter Ausdruck ist jeder Ausdruck, dessen Auswertung nicht eine der folgenden Sprachkonstrukte auswerten würde:

Sprachkonstrukt Version Paper(s)
der this Zeiger, außer in einer constexpr Funktion die als Teil des Ausdrucks ausgewertet wird, oder wenn er in einem impliziten oder expliziten Klassenmitglied-Zugriffsausdruck erscheint N2235
ein Kontrollfluss, der durch eine Deklaration einer Block-Variable mit static oder thread Speicherdauer verläuft, die nicht in konstanten Ausdrücken verwendbar ist (since C++23) P2242R3
  1. a function call expression that calls a function (or a constructor) that is not declared constexpr
    constexpr int n = std::numeric_limits<int>::max(); // OK: max() ist constexpr
    constexpr int m = std::time(nullptr); // Fehler: std::time() ist nicht constexpr
  2. a function call to a constexpr function which is declared, but not defined
  3. a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy constexpr-Funktion/-Konstruktor requirements.
  4. a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
  5. an expression that would exceed the implementation-defined limits
  6. an expression whose evaluation leads to any form of core language undefined oder fehlerhaft (seit C++26) behavior, except for any potential undefined behavior introduced by Standardattribute .
    constexpr double d1 = 2.0 / 1.0; // OK
    constexpr double d2 = 2.0 / 0.0; // Fehler: nicht definiert
    constexpr int n = std::numeric_limits<int>::max() + 1; // Fehler: Überlauf
    int x, y, z[30];
    constexpr auto e1 = &y - &x;        // Fehler: undefiniert
    constexpr auto e2 = &z[20] - &z[3]; // OK
    constexpr std::bitset<2> a; 
    constexpr bool b = a[2]; // UB, aber unbestimmt ob erkannt
  7. (bis C++17) a Lambda-Ausdruck
  8. an lvalue-to-rvalue implizite Konvertierung unless applied to...
    1. ein glvalue vom Typ (möglicherweise cv-qualifiziert) std::nullptr_t
    2. ein nicht-flüchtiger Literal-Typ-glvalue, der ein Objekt bezeichnet, das in konstanten Ausdrücken verwendbar ist
      int main()
      {
          const std::size_t tabsize = 50;
          int tab[tabsize]; // OK: tabsize ist ein konstanter Ausdruck
                            // weil tabsize in konstanten Ausdrücken verwendbar ist
                            // da es const-qualifizierten integralen Typ hat und
                            // sein Initialisierer ein konstanter Initialisierer ist
          std::size_t n = 50;
          const std::size_t sz = n;
          int tab2[sz]; // Fehler: sz ist kein konstanter Ausdruck
                        // weil sz nicht in konstanten Ausdrücken verwendbar ist
                        // da sein Initialisierer kein konstanter Initialisierer war
      }
    3. ein nicht-flüchtiger Literal-Typ-glvalue, der sich auf ein nicht-flüchtiges Objekt bezieht, dessen Lebensdauer innerhalb der Auswertung dieses Ausdrucks begann
  9. an lvalue-to-rvalue implizite Konvertierung or modification applied to a non-active member of a Union or its subobject (even if it shares a common initial sequence with the active member)
  10. an lvalue-to-rvalue implicit conversion on an object dessen Wert unbestimmt ist
  11. an invocation of implicit copy/move constructor/assignment for a union whose active member is mutable (if any), with lifetime beginning outside the evaluation of this expression
  12. (bis C++20) an assignment expression that would change the active member of a union
  13. conversion from Zeiger auf void to a pointer-to-object type T* es sei denn, der Zeiger hält einen Nullzeigerwert oder zeigt auf ein Objekt, dessen Typ ähnlich zu T ist (seit C++26)
  14. dynamic_cast dessen Operand ein Glvalue ist, der sich auf ein Objekt bezieht, dessen dynamischer Typ constexpr-unbekannt ist (since C++20)
  15. reinterpret_cast
  16. (bis C++20) pseudo-destructor call
  17. (bis C++14) an increment or a decrement operator
  18. (seit C++14) modification of an object, unless the object has non-volatile literal type and its lifetime began within the evaluation of the expression
    constexpr int incr(int& n)
    {
        return ++n;
    }
    constexpr int g(int k)
    {
        constexpr int x = incr(k); // Fehler: incr(k) ist kein Kern-Konstantenausdruck
                                   // weil die Lebensdauer von k
                                   // außerhalb des Ausdrucks incr(k) begann
        return x;
    }
    constexpr int h(int k)
    {
        int x = incr(k); // OK: x muss nicht mit einem Kern-Konstantenausdruck
                         // initialisiert werden
        return x;
    }
    constexpr int y = h(1); // OK: initialisiert y mit dem Wert 2
                            // h(1) ist ein Kern-Konstantenausdruck, weil
                            // die Lebensdauer von k innerhalb des Ausdrucks h(1) beginnt
  19. (seit C++20) a destructor call or pseudo destructor call for an object whose lifetime did not begin within the evaluation of this expression
  20. a typeid expression applied to a glvalue of polymorphic type und dieser Glvalue verweist auf ein Objekt, dessen dynamischer Typ constexpr-unbekannt ist (seit C++20)
  21. a new Ausdruck , es sei denn, eine der folgenden Bedingungen ist erfüllt: (seit C++20)
    • Die ausgewählte Allokationsfunktion ist eine ersetzbare globale Allokationsfunktion und der allokierte Speicher wird innerhalb der Auswertung dieses Ausdrucks freigegeben.
    (since C++20)
    • Die ausgewählte Allokationsfunktion ist eine nicht-allokierende Form mit einem allokierten Typ T , und das Platzierungsargument erfüllt alle folgenden Bedingungen:
    • Es zeigt auf:
    • ein Objekt, dessen Typ ähnlich zu T ist, falls T kein Array-Typ ist, oder
    • das erste Element eines Objekts eines Typs ähnlich zu T , falls T ein Array-Typ ist.
    • Es zeigt auf Speicher, dessen Lebensdauer innerhalb der Auswertung dieses Ausdrucks begann.
    (since C++26)
  22. a delete Ausdruck , es sei denn, es gibt einen Speicherbereich frei, der innerhalb der Auswertung dieses Ausdrucks alloziert wurde (since C++20)
  23. (seit C++20) Coroutines: an Await-Ausdruck or a Yield-Ausdruck
  24. (seit C++20) a Drei-Wege-Vergleich when the result is unspecified
  25. an equality or relational operator whose result is unspecified
  26. (bis C++14) an assignment or a compound assignment operator
  27. (bis C++26) ein throw-Ausdruck
  28. (seit C++26) die Konstruktion eines Ausnahmeobjekts, es sei denn, das Ausnahmeobjekt und alle seine impliziten Kopien, die durch Aufrufe von std::current_exception oder std::rethrow_exception erstellt wurden, werden innerhalb der Auswertung dieses Ausdrucks zerstört
    constexpr void check(int i)
    {
        if (i < 0)
            throw i;
    }
    constexpr bool is_ok(int i)
    {
        try {
            check(i);
        } catch (...) {
            return false;
        }
        return true;
    }
    constexpr bool always_throw()
    {
        throw 12;
        return true;
    }
    static_assert(is_ok(5)); // OK
    static_assert(!is_ok(-1)); // OK seit C++26
    static_assert(always_throw()); // Fehler: ungefangene Ausnahme
  29. eine asm-Deklaration
  30. ein Aufruf des va_arg Makros
  31. eine goto Anweisung
  32. ein dynamic_cast oder typeid Ausdruck oder new Ausdruck (seit C++26) der eine Ausnahme werfen würde wo keine Definition des Ausnahmetyps erreichbar ist (seit C++26)
  33. innerhalb eines Lambda-Ausdrucks, eine Referenz auf this oder auf eine Variable, die außerhalb dieses Lambdas definiert ist, wenn diese Referenz eine ODR-Nutzung wäre
    void g()
    {
        const int n = 0;
        constexpr int j = *&n; // OK: außerhalb eines Lambda-Ausdrucks
        [=]
        {
            constexpr int i = n;   // OK: 'n' wird hier nicht ODR-genutzt und nicht erfasst.
            constexpr int j = *&n; // Ungültig: '&n' wäre eine ODR-Nutzung von 'n'.
        };
    }

    Hinweis: Wenn die ODR-Nutzung in einem Funktionsaufruf an einen Closure stattfindet, bezieht sie sich nicht auf this oder auf eine umschließende Variable, da sie auf ein Datenmitglied des Closures zugreift

    // OK: 'v' & 'm' werden ODR-genutzt, kommen aber nicht in einem konstanten Ausdruck
    // innerhalb des verschachtelten Lambdas vor
    auto monad = [](auto v){ return [=]{ return v; }; };
    auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; };
    // OK, Erfassungen von automatischen Objekten, die während der konstanten Ausdrucksauswertung erstellt wurden, zu haben.
    static_assert(bind(monad(2))(monad)() == monad(2)());
    (seit C++17)

Zusätzliche Anforderungen

Selbst wenn ein Ausdruck E nichts der oben genannten Dinge auswertet, ist implementierungsdefiniert, ob E ein Kernkonstanter Ausdruck ist, wenn die Auswertung von E zu Laufzeit-undefiniertem Verhalten führen würde.

Selbst wenn ein Ausdruck E nichts der oben genannten Dinge auswertet, ist es unspezifiziert, ob E ein Core Constant Expression ist, wenn die Auswertung von E eines der folgenden Dinge auswerten würde:

Für die Bestimmung, ob ein Ausdruck ein Kernkonstantenausdruck ist, wird die Auswertung des Rumpfes einer Elementfunktion von std:: allocator < T > ignoriert, falls T ein Literaltyp ist.

Zum Zweck der Bestimmung, ob ein Ausdruck ein Kernkonstanter Ausdruck ist, wird die Auswertung eines Aufrufs eines trivialen Kopier-/Verschiebekonstruktors oder einer Kopier-/Verschiebezuweisung einer Union als Kopieren/Verschieben des aktiven Members der Union betrachtet, falls vorhanden.

Für die Bestimmung, ob ein Ausdruck ein Kernkonstantenausdruck ist, hat die Auswertung eines Identifikatorausdrucks, der eine structured binding bd benennt, die folgende Semantik:

  • Wenn bd ein L-Wert ist, der auf das an eine erfundene Referenz ref gebundene Objekt verweist, ist das Verhalten so, als ob ref nominiert würde.
  • Andernfalls, wenn bd ein Array-Element benennt, ist das Verhalten das der Auswertung von e [ i ] , wobei e der Name der Variable ist, die aus dem Initialisierer der structured binding-Deklaration initialisiert wurde, und i der Index des Elements ist, auf das bd verweist.
  • Andernfalls, wenn bd ein Klassenmitglied benennt, ist das Verhalten das der Auswertung von e. m , wobei e der Name der Variable ist, die aus dem Initialisierer der structured binding-Deklaration initialisiert wurde, und m der Name des Mitglieds ist, auf das bd verweist.
(seit C++26)

Während der Auswertung des Ausdrucks als Kernkonstanteausdruck werden alle Identifikatorausdrücke und Verwendungen von * this , die sich auf ein Objekt oder eine Referenz beziehen, deren Lebensdauer außerhalb der Auswertung des Ausdrucks begann, so behandelt, als würden sie sich auf eine spezifische Instanz dieses Objekts oder dieser Referenz beziehen, deren Lebensdauer und die aller Teilobjekte (einschließlich aller Union-Mitglieder) die gesamte Konstantenauswertung umfasst.

  • Für ein solches Objekt das nicht in konstanten Ausdrücken verwendbar ist (seit C++20) , ist der dynamische Typ des Objekts constexpr-unknown .
  • Für eine solche Referenz die nicht in konstanten Ausdrücken verwendbar ist (seit C++20) , wird die Referenz so behandelt, als würde sie an ein nicht näher spezifiziertes Objekt des referenzierten Typs gebunden, dessen Lebensdauer und die aller Unterobjekte die gesamte konstante Auswertung umfasst und dessen dynamischer Typ constexpr-unknown ist.

Integraler konstanter Ausdruck

Integraler konstanter Ausdruck ist ein Ausdruck vom integralen oder unbegrenzten Aufzählungstyp, der implizit in einen Prvalue konvertiert wird, wobei der konvertierte Ausdruck ein Kernkonstanter Ausdruck ist.

Wenn ein Ausdruck vom Klassentyp an einer Stelle verwendet wird, wo ein integraler konstanter Ausdruck erwartet wird, wird der Ausdruck kontextuell implizit konvertiert zu einem integralen Typ oder einem unbegrenzten Aufzählungstyp.

Konvertierter konstanter Ausdruck

Ein konvertierter konstanter Ausdruck vom Typ T ist ein Ausdruck, der implizit konvertiert wird zum Typ T , wobei der konvertierte Ausdruck ein konstanter Ausdruck ist und die implizite Konvertierungssequenz nur folgende Elemente enthält:

(seit C++17)

Und falls eine Referenzbindung stattfindet, kann es nur eine direkte Bindung sein.

Die folgenden Kontexte erfordern einen konvertierten konstanten Ausdruck:

(seit C++14)
(seit C++26)

Ein kontextuell umgewandelter konstanter Ausdruck vom Typ bool ist ein Ausdruck, der kontextuell zu bool umgewandelt wird , wobei der umgewandelte Ausdruck ein konstanter Ausdruck ist und die Umwandlungssequenz nur die oben genannten Konvertierungen enthält.

Die folgenden Kontexte erfordern einen kontextuell konvertierten konstanten Ausdruck vom Typ bool :

(bis C++23)
(seit C++17)
(bis C++23)
(seit C++20)


Bestandteile

Die Bestandteilswerte eines Objekts obj werden wie folgt definiert:

Die Bestandteilsreferenzen eines Objekts obj umfassen folgende Referenzen:

  • alle direkten Mitglieder von obj , die Referenztyp haben
  • die Bestandteilsreferenzen aller direkten Unterobjekte von obj außer inaktiven Union-Mitgliedern

Die Bestandteilswerte und Bestandteilsreferenzen einer Variable var werden wie folgt definiert:

  • Wenn var ein Objekt deklariert, sind die Bestandteilswerte und -referenzen die Bestandteilswerte und -referenzen dieses Objekts.
  • Wenn var eine Referenz deklariert, ist die Bestandteilsreferenz diese Referenz.

Für jede Bestandteilsreferenz ref einer Variable var gilt: Wenn ref an ein temporäres Objekt oder dessen Unterobjekt gebunden ist, dessen Lebensdauer auf die von ref verlängert wurde, dann sind die Bestandteilswerte und -referenzen dieses temporären Objekts ebenfalls Bestandteilswerte und -referenzen von var , rekursiv.

Constexpr-repräsentierbare Entitäten

Objekte mit statischer Speicherdauer sind constexpr-referenzierbar an jedem Punkt im Programm.

Ein Objekt obj mit automatischer Speicherdauer ist constexpr-referenzierbar von einem Punkt P aus, wenn der kleinste Gültigkeitsbereich , der die Variable var umschließt, und der kleinste Gültigkeitsbereich, der P umschließt, derselbe Funktionsparameter-Gültigkeitsbereich sind, der nicht mit der Parameterliste eines requires -Ausdrucks assoziiert ist, wobei var die Variable ist, die dem vollständigen Objekt von obj entspricht, oder die Variable, auf deren Lebensdauer die von obj verlängert wurde.

Ein Objekt oder eine Referenz x ist constexpr-repräsentierbar an einem Punkt P , wenn alle folgenden Bedingungen erfüllt sind:

  • Für jeden Bestandteilswert von x , der auf ein Objekt obj zeigt, ist obj constexpr-referenzierbar von P .
  • Für jeden Bestandteilswert von x , der über ein Objekt obj hinauszeigt, ist obj constexpr-referenzierbar von P .
  • Für jede Bestandteilsreferenz von x , die auf ein Objekt obj verweist, ist obj constexpr-referenzierbar von P .
(seit C++26)

Konstant initialisierte Entitäten

Eine Variable oder ein temporäres Objekt obj ist konstant-initialisiert , wenn alle folgenden Bedingungen erfüllt sind:

  • Es hat entweder einen Initialisierer oder sein Typ ist const-default-constructible .
  • Der full-expression seiner Initialisierung ist ein konstanter Ausdruck im Kontext der Anforderung eines konstanten Ausdrucks, außer dass, wenn obj ein Objekt ist, dieser vollständige Ausdruck auch constexpr constructors für obj und seine Unterobjekte aufrufen darf, selbst wenn diese Objekte von nicht-literalen Klassentypen sind.
(bis C++26)

Eine Variable var ist konstant-initialisierbar , wenn alle folgenden Bedingungen erfüllt sind:

  • Der full-expression ihrer Initialisierung ist ein konstanter Ausdruck im Kontext der Anforderung eines konstanten Ausdrucks, wobei alle contract assertions die "ignore"-Auswertungssemantik verwenden.
  • Unmittelbar nach der initialisierenden Deklaration von var ist das durch var deklarierte Objekt oder die Referenz constexpr-repräsentierbar.
  • Wenn das Objekt oder die Referenz x , das/die durch var deklariert wird, eine statische oder Thread-Speicherdauer hat, ist x constexpr-repräsentierbar am nächsten Punkt, dessen unmittelbarer Gültigkeitsbereich ein Namensbereichs-Gültigkeitsbereich ist, der auf die initialisierende Deklaration von var folgt.

Eine konstant-initialisierbare Variable ist konstant-initialisiert , wenn sie entweder einen Initialisierer hat oder ihr Typ const-default-constructible ist.

(seit C++26)

Verwendbar in konstanten Ausdrücken

Eine Variable ist potenziell-konstant , wenn sie eine constexpr Variable ist oder einen Referenz- oder nicht-flüchtigen const-qualifizierten Ganzzahl- oder Aufzählungstyp besitzt.

Eine konstant initialisierte potenziell konstante Variable var ist in konstanten Ausdrücken verwendbar an einem Punkt P , falls var ’s initialisierende Deklaration D von P erreichbar ist und eine der folgenden Bedingungen erfüllt ist:

  • var ist eine constexpr -Variable.
  • var ist nicht mit einem TU-lokalen Wert initialisiert.
  • P befindet sich in derselben Übersetzungseinheit wie D .

Ein Objekt oder eine Referenz ist in konstanten Ausdrücken verwendbar an einem Punkt P , wenn es eine der folgenden Entitäten ist:

  • eine Variable, die in konstanten Ausdrücken an P verwendbar ist
  • ein temporäres Objekt eines nicht-flüchtigen const-qualifizierten Literaltyps, dessen Lebensdauer auf die einer Variable erweitert wird, die in konstanten Ausdrücken an P verwendbar ist
  • ein template parameter object
  • ein string literal -Objekt
  • ein nicht veränderbares Unterobjekt eines der oben genannten
  • ein Referenzmember eines der oben genannten
(bis C++26)

Ein Objekt oder eine Referenz ist potenziell in konstanten Ausdrücken verwendbar an einem Punkt P , wenn es eine der folgenden Entitäten ist:

  • eine Variable, die in konstanten Ausdrücken an P verwendbar ist
  • ein temporäres Objekt eines nicht-flüchtigen const-qualifizierten Literaltyps, dessen Lebensdauer auf die einer Variable erweitert wird, die in konstanten Ausdrücken an P verwendbar ist
  • ein template parameter object
  • ein string literal -Objekt
  • ein nicht veränderbares Unterobjekt eines der oben genannten
  • ein Referenzmember eines der oben genannten

Ein Objekt oder eine Referenz ist in konstanten Ausdrücken verwendbar an einem Punkt P , wenn es ein Objekt oder eine Referenz ist, das/die potenziell in konstanten Ausdrücken an P verwendbar ist und an P constexpr-repräsentierbar ist.

(seit C++26)

Offensichtlich konstant ausgewertete Ausdrücke

Die folgenden Ausdrücke (einschließlich Konvertierungen in den Zieltyp) sind offensichtlich konstant ausgewertet :

Ob eine Auswertung in einem offensichtlich konstanten Kontext stattfindet, kann durch std::is_constant_evaluated und if consteval (seit C++23) erkannt werden.

(seit C++20)

Für die konstante Auswertung benötigte Funktionen und Variablen

Folgende Ausdrücke oder Konvertierungen sind potenziell konstant ausgewertet :

Eine Funktion ist für konstante Auswertung benötigt wenn sie eine constexpr-Funktion ist und benannt durch einen Ausdruck, der potenziell konstant ausgewertet wird.

Eine Variable ist für konstante Auswertung benötigt wenn sie entweder eine constexpr-Variable ist oder einen nicht-flüchtigen const-qualifizierten integralen Typ oder Referenztyp hat und der Identifikatorausdruck der sie bezeichnet potenziell konstant ausgewertet wird.

Definition einer defaulted-Funktion und Instanziierung einer Funktions-Template -Spezialisierung oder Variablen-Template -Spezialisierung (since C++14) werden ausgelöst, wenn die Funktion oder Variable (since C++14) für konstante Auswertung benötigt wird.

Konstanter Teilausdruck

Ein konstanter Teilausdruck ist ein Ausdruck, dessen Auswertung als Teilausdruck eines Ausdrucks e nicht verhindern würde, dass e ein Core Constant Expression ist, wobei e keiner der folgenden Ausdrücke ist:

(seit C++20)

Hinweise

Feature-Test-Makro Wert Std Feature
__cpp_constexpr_in_decltype 201711L (C++20)
(DR11)
Generierung von Funktions- und Variablendefinitionen, wenn für konstante Auswertung benötigt
__cpp_constexpr_dynamic_alloc 201907L (C++20) Operationen für dynamische Speicherdauer in constexpr Funktionen
__cpp_constexpr 202306L (C++26) constexpr Cast von void * : in Richtung constexpr Type Erasure
202406L (C++26) constexpr Placement new und new [ ]
__cpp_constexpr_exceptions 202411L (C++26) constexpr Exceptions: [1] , [2]

Beispiel

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 94 C++98 arithmetische konstante Ausdrücke konnten
keine Variablen und statische Datenelemente enthalten
jetzt möglich
CWG 366 C++98 Ausdrücke mit String-Literalen
könnten konstante Integralausdrücke sein
sie sind es nicht
CWG 457 C++98 Ausdrücke mit flüchtigen Variablen
könnten konstante Integralausdrücke sein
sie sind es nicht
CWG 1293 C++11 Es war unklar, ob String-Literale
in konstanten Ausdrücken verwendbar sind
Sie sind verwendbar
CWG 1311 C++11 volatile-Glvalues konnten in konstanten Ausdrücken verwendet werden verboten
CWG 1312 C++11 reinterpret_cast ist in konstanten Ausdrücken verboten,
aber Casts zu und von void * könnten denselben Effekt erzielen
verbotene Konvertierungen
vom Typ cv void * zu
einem Zeiger-auf-Objekt-Typ
CWG 1313 C++11 undefiniertes Verhalten war erlaubt;
alle Zeigersubtraktionen waren verboten
UB verboten; Zeigersubtraktion
innerhalb desselben Arrays erlaubt
CWG 1405 C++11 für Objekte, die in konstanten Ausdrücken verwendbar sind,
waren ihre veränderlichen Unterobjekte ebenfalls verwendbar
sie sind nicht verwendbar
CWG 1454 C++11 Das Übergeben von Konstanten durch constexpr
Funktionen über Referenzen war nicht erlaubt
erlaubt
CWG 1455 C++11 konvertierte konstante Ausdrücke konnten nur Prvalues sein können Lvalues sein
CWG 1456 C++11 Ein Adresskonstantenausdruck konnte nicht
die Adresse direkt nach dem Ende eines Arrays bezeichnen
erlaubt
CWG 1535 C++11 ein typeid -Ausdruck, dessen Operand von einem
polymorphen Klassentyp war, war kein Core Constant
Expression, selbst wenn keine Laufzeitprüfung beteiligt war
die Operandenbeschränkung
ist auf L-Werte von
polymorphen Klassentypen begrenzt
CWG 1581 C++11 für die konstante Auswertung benötigte Funktionen waren
nicht definiert oder instanziiert werden mussten
erforderlich
CWG 1613 C++11 Kernkonstantenausdrücke konnten beliebige
odr-verwendete Referenzen innerhalb von Lambda-Ausdrücken auswerten
einige Referenzen konnten
nicht ausgewertet werden
CWG 1694 C++11 Das Binden des Werts eines temporären Objekts an eine Referenz mit statischer
Speicherdauer war ein konstanter Ausdruck
es ist kein
konstanter Ausdruck
CWG 1872 C++11 Kernkonstantenausdrücke könnten constexpr Funktions-Template-Instanziierungen aufrufen,
die die constexpr Funktionsanforderungen nicht erfüllen
solche Instanziierungen
können nicht aufgerufen werden
CWG 1952 C++11 Standardbibliothek undefinierte Verhaltensweisen
mussten diagnostiziert werden
nicht spezifiziert ob
sie diagnostiziert werden
CWG 2022 C++98 die Bestimmung von konstanten Ausdrücken könnte
davon abhängen, ob Copy Elision durchgeführt wird
gehe davon aus, dass Copy Elision
immer durchgeführt wird
CWG 2126 C++11 Konstant initialisierte, lebensdauer-verlängerte Temporaries von const-
qualifizierten Literaltypen waren nicht in konstanten Ausdrücken verwendbar
verwendbar
CWG 2129 C++11 Ganzzahlige Literale waren keine konstanten Ausdrücke sie sind es
CWG 2167 C++11 Nicht-Mitglied-Referenzen lokal zu einer Auswertung
machten die Auswertung nicht-konstexpr
Nicht-Mitglied-
Referenzen erlaubt
CWG 2278 C++98 die Lösung von CWG Issue 2022 war nicht implementierbar annehmen, dass Copy Elision
niemals durchgeführt wird
CWG 2299 C++14 Es war unklar, ob Makros in <cstdarg>
bei konstanter Auswertung verwendet werden können
va_arg verboten,
va_start nicht spezifiziert
CWG 2400 C++11 Aufruf einer constexpr-Virtualfunktion auf einem Objekt, das nicht
in konstanten Ausdrücken verwendbar ist und dessen Lebensdauer außerhalb
des Ausdrucks begann, der den Aufruf enthält, könnte ein konstanter Ausdruck sein
es ist kein
konstanter Ausdruck
CWG 2490 C++20 (Pseudo-)Destruktoraufrufe fehlten
Einschränkungen bei konstanter Auswertung
Einschränkung hinzugefügt
CWG 2552 C++23 bei der Auswertung eines konstanten Kernausdrucks konnte der Kontrollfluss
nicht durch eine Deklaration einer Nicht-Block-Variable verlaufen
es kann
CWG 2558 C++11 Ein unbestimmter Wert könnte ein konstanter Ausdruck sein kein konstanter Ausdruck
CWG 2647 C++20 Variablen von volatile-qualifizierten Typen könnten potenziell konstant sein sind sie nicht
CWG 2763 C++11 die Verletzung von [[ noreturn ]] musste nicht
während der konstanten Auswertung erkannt werden
erforderlich
CWG 2851 C++11 konvertierte konstante Ausdrücke erlaubten
keine Gleitkomma-Konvertierungen
nicht-verengende
Gleitkomma-Konvertierungen erlauben
CWG 2907 C++11 Kernkonstantenausdrücke konnten keine
Lvalue-zu-Rvalue-Konvertierungen auf std::nullptr_t -Glvalues anwenden
können solche
Konvertierungen anwenden
CWG 2909 C++20 eine Variable ohne Initialisierer konnte nur
konstant-initialisiert werden, wenn ihre Standardinitialisierung
zur Durchführung einer Initialisierung führt
kann nur konstant-
initialisiert werden, wenn ihr Typ
const-default-initializable ist
CWG 2924 C++11
C++23
Es war nicht spezifiziert, ob ein Ausdruck, der gegen
die Constraints von [[ noreturn ]] (C++11) oder
[[ assume ]] (C++23) verstößt, ein Core Constant Expression ist
Es ist
implementierungsdefiniert
P2280R4 C++11 Die Auswertung eines Ausdrucks, der einen Identifikatorausdruck
oder * this enthält, der sich auf ein Objekt oder eine Referenz bezieht, dessen Lebensdauer
außerhalb dieser Auswertung begann, ist keine konstante Ausdruck
es kann ein
konstanter Ausdruck sein

Siehe auch

constexpr Spezifizierer (C++11) gibt an, dass der Wert einer Variable oder Funktion zur Kompilierzeit berechnet werden kann
(C++11) (deprecated in C++17) (removed in C++20)
prüft, ob ein Typ ein Literaltyp ist
(Klassentemplate)
C-Dokumentation für Konstante Ausdrücke