constexpr
specifier
(since C++11)
-
-
constexpr- gibt an, dass der Wert einer Variable , structured binding (since C++26) oder Funktion in constant expressions erscheinen kann
-
Inhaltsverzeichnis |
Erklärung
Der constexpr -Spezifizierer deklariert, dass es möglich ist, den Wert der Entitäten zur Übersetzungszeit auszuwerten. Solche Entitäten können dann verwendet werden, wo nur konstante Ausdrücke zur Übersetzungszeit erlaubt sind (sofern entsprechende Funktionsargumente gegeben sind).
Ein constexpr -Spezifizierer, der in einer Objektdeklaration oder nicht-statischen Memberfunktion (bis C++14) verwendet wird, impliziert const .
Ein constexpr Spezifizierer, der in der ersten Deklaration einer Funktion oder eines static Datenelements (seit C++17) verwendet wird, impliziert inline . Wenn eine Deklaration einer Funktion oder Funktionsvorlage einen constexpr Spezifizierer besitzt, dann muss jede Deklaration diesen Spezifizierer enthalten.
constexpr Variable
Eine Variable oder Variablen-Template (seit C++14) kann als constexpr deklariert werden, wenn alle folgenden Bedingungen erfüllt sind:
- Die Deklaration ist eine Definition .
- Sie ist von einem literal type .
- Sie wird (durch die Deklaration) initialisiert.
|
(bis C++26) |
|
(seit C++26) |
|
Wenn eine constexpr Variable nicht translation-unit-local ist, sollte sie nicht so initialisiert werden, dass sie auf eine translation-unit-local Entität verweist, die in konstanten Ausdrücken verwendbar ist, noch ein Unterobjekt haben, das auf eine solche Entität verweist. Eine solche Initialisierung ist in einer Module Interface Unit (außerhalb ihres Private Module Fragment , falls vorhanden) oder einer Modulpartition nicht erlaubt und in jedem anderen Kontext als veraltet eingestuft. |
(seit C++20) |
constexpr Funktion
Eine Funktion oder Funktionsvorlage kann als constexpr deklariert werden.
Eine Funktion ist constexpr-suitable wenn alle folgenden Bedingungen erfüllt sind:
|
(bis C++20) |
|
(bis C++23) |
|
(seit C++20) |
|
(bis C++14) | ||
|
(seit C++14)
(bis C++23) |
Mit Ausnahme von instanziierten constexpr Funktionen müssen nicht-templatisierte constexpr Funktionen constexpr-tauglich sein.
|
Für eine Nicht-Konstruktor- constexpr Funktion, die weder defaulted noch templated ist, wenn keine Argumentwerte existieren, sodass ein Aufruf der Funktion ein ausgewerteter Subausdruck eines Core Constant Expression sein könnte, ist das Programm ill-formed, keine Diagnose erforderlich. Für eine templated constexpr Funktion, wenn keine Spezialisierung der Funktion/Klassen-Template die templated Funktion constexpr-suitable machen würde, wenn sie als nicht-templated Funktion betrachtet wird, ist das Programm ill-formed, keine Diagnose erforderlich. |
(bis C++23) |
Ein Aufruf einer constexpr -Funktion in einem bestimmten Kontext erzeugt in jeder Hinsicht dasselbe Ergebnis wie ein Aufruf einer äquivalenten Nicht- constexpr -Funktion im selben Kontext, mit folgenden Ausnahmen:
- Ein Aufruf einer constexpr -Funktion kann in einem konstanten Ausdruck erscheinen.
- Copy Elision wird nicht in einem konstanten Ausdruck durchgeführt.
constexpr Konstruktor
Zusätzlich zu den Anforderungen an constexpr -Funktionen muss ein Konstruktor alle folgenden Bedingungen erfüllen, um für constexpr geeignet zu sein:
|
(bis C++23) |
- Die Klasse hat keine virtuelle Basisklasse .
|
Für einen constexpr -Konstruktor, der weder als Standard definiert noch als Template implementiert ist, gilt: Falls keine Argumentwerte existieren, bei denen ein Aufruf der Funktion ein ausgewerteter Teilausdruck des Initialisierungsvollausdrucks eines Objekts sein könnte, das einer konstanten Expression unterliegt, ist das Programm fehlerhaft, ohne dass eine Diagnose erforderlich ist. |
(bis C++23) |
constexpr Destruktor
|
Destruktoren können nicht constexpr sein, aber ein trivialer Destruktor kann in konstanten Ausdrücken implizit aufgerufen werden. |
(bis C++20) | ||
|
Zusätzlich zu den Anforderungen an constexpr -Funktionen muss ein Destruktor alle folgenden Bedingungen erfüllen, um constexpr-fähig zu sein:
|
(seit C++20) |
Hinweise
|
Da der
constexpr int f(); constexpr bool b1 = noexcept(f()); // false, undefined constexpr function constexpr int f() { return 0; } constexpr bool b2 = noexcept(f()); // true, f() is a constant expression |
(bis C++17) |
|
Es ist möglich, eine constexpr-Funktion zu schreiben, deren Aufruf niemals die Anforderungen eines Kernkonstantenausdrucks erfüllen kann: void f(int& i) // not a constexpr function { i = 0; } constexpr void g(int& i) // well-formed since C++23 { f(i); // unconditionally calls f, cannot be a constant expression } |
(since C++23) |
Constexpr-Konstruktoren sind für Klassen erlaubt, die keine Literaltypen sind. Beispielsweise ist der Standardkonstruktor von std::shared_ptr constexpr, was eine konstante Initialisierung ermöglicht.
Referenzvariablen können als constexpr deklariert werden (ihre Initialisierer müssen Referenzkonstantenausdrücke sein):
static constexpr int const& x = 42; // constexpr-Referenz auf ein const int-Objekt // (das Objekt hat aufgrund der Lebensdauerverlängerung // durch eine statische Referenz statische Speicherdauer)
|
Obwohl try -Blöcke und Inline-Assembly in constexpr-Funktionen erlaubt sind, ist das Werfen von Ausnahmen die nicht abgefangen werden (seit C++26) oder das Ausführen der Assembly in einem konstanten Ausdruck weiterhin nicht gestattet. Wenn eine Variable eine konstante Destruktion besitzt, ist es nicht erforderlich, Maschinencode zu generieren, um ihren Destruktor aufzurufen, selbst wenn ihr Destruktor nicht trivial ist. Eine nicht-Lambda, nicht-Spezial-Member und nicht-templatisierte constexpr-Funktion kann nicht implizit zu einer Immediate-Funktion werden. Benutzer müssen sie explizit als consteval markieren, um eine solche beabsichtigte Funktionsdefinition wohlgeformt zu machen. |
(seit C++20) |
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_constexpr
|
200704L
|
(C++11) | constexpr |
201304L
|
(C++14) | Gelockerte constexpr , nicht- const constexpr Methoden | |
201603L
|
(C++17) | Constexpr-Lambda | |
201907L
|
(C++20) | Triviale Standardinitialisierung und Asm-Deklaration in constexpr Funktionen | |
202002L
|
(C++20) | Ändern des aktiven Members einer Union in konstanter Auswertung | |
202110L
|
(C++23) | Nicht- Literal Variablen, Labels und goto Anweisungen in constexpr-Funktionen | |
202207L
|
(C++23) | Lockerung einiger constexpr Einschränkungen | |
202211L
|
(C++23) | Zulassung von static constexpr Variablen in constexpr Funktionen | |
202306L
|
(C++26) | Constexpr-Cast von void * : in Richtung constexpr Type Erasure | |
__cpp_constexpr_in_decltype
|
201711L
|
(C++11)
(DR) |
Erzeugung 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 |
Schlüsselwörter
Beispiel
Definiert C++11/14 constexpr Funktionen, die Fakultäten berechnen; definiert einen Literaltyp, der String-Literale erweitert:
#include <iostream> #include <stdexcept> // C++11 constexpr-Funktionen verwenden Rekursion anstelle von Iteration constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } // C++14 constexpr-Funktionen können lokale Variablen und Schleifen verwenden #if __cplusplus >= 201402L constexpr int factorial_cxx14(int n) { int res = 1; while (n > 1) res *= n--; return res; } #endif // C++14 // Eine Literalklasse class conststr { const char* p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {} // constexpr-Funktionen signalisieren Fehler durch Auslösen von Ausnahmen // in C++11 müssen sie dies über den bedingten Operator ?: tun constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } }; // C++11 constexpr-Funktionen mussten alles in einer einzigen return-Anweisung unterbringen // (C++14 hat diese Anforderung nicht) constexpr std::size_t countlower(conststr s, std::size_t n = 0, std::size_t c = 0) { return n == s.size() ? c : 'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) : countlower(s, n + 1, c); } // Eine Ausgabefunktion, die eine Kompilierzeitkonstante erfordert, zum Testen template<int n> struct constN { constN() { std::cout << n << '\n'; } }; int main() { std::cout << "4! = "; constN<factorial(4)> out1; // zur Kompilierzeit berechnet volatile int k = 8; // Optimierung mit volatile verhindern std::cout << k << "! = " << factorial(k) << '\n'; // zur Laufzeit berechnet std::cout << "Die Anzahl der Kleinbuchstaben in \"Hello, world!\" ist "; constN<countlower("Hello, world!")> out2; // implizit zu conststr konvertiert constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; constexpr int length_a = sizeof a / sizeof(int); // std::size(a) in C++17, // std::ssize(a) in C++20 std::cout << "Array der Länge " << length_a << " hat Elemente: "; for (int i = 0; i < length_a; ++i) std::cout << a[i] << ' '; std::cout << '\n'; }
Ausgabe:
4! = 24 8! = 40320 Die Anzahl der Kleinbuchstaben in "Hello, world!" ist 9 Array der Länge 12 hat Elemente: 0 1 2 3 4 5 6 7 8 0 0 0
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Veröffentlichtes Verhalten | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1358 | C++11 |
templatisierte
constexpr
Funktionen benötigten ebenfalls
mindestens einen gültigen Argumentwert |
nicht erforderlich |
| CWG 1359 | C++11 |
constexpr
Union-Konstruktoren
müssen alle Datenelemente initialisieren |
initialisiert genau ein Datenelement
für nicht-leere Unions |
| CWG 1366 | C++11 |
Klassen mit
constexpr
Konstruktoren, deren Funktionskörper
= default oder = delete sind, könnten virtuelle Basisklassen haben |
solche Klassen können weder
virtuelle Basisklassen haben |
| CWG 1595 | C++11 |
constexpr
delegierende Konstruktoren erforderten
dass alle beteiligten Konstruktoren constexpr sind |
erfordert nur dass der Ziel-
konstruktor constexpr ist |
| CWG 1712 | C++14 |
eine
constexpr
Variablenvorlage musste in
allen Deklarationen den constexpr Spezifizierer enthalten [1] |
nicht mehr erforderlich |
| CWG 1911 | C++11 | constexpr Konstruktoren für Nicht-Literal-Typen waren nicht erlaubt | erlaubt bei konstanter Initialisierung |
| CWG 2004 | C++11 |
Kopieren/Verschieben einer Union mit mutable-Member
war in konstanten Ausdrücken erlaubt |
mutable-Varianten disqualifizieren
implizites Kopieren/Verschieben |
| CWG 2022 | C++98 |
ob äquivalente
constexpr
und Nicht-
constexpr
Funktionen gleiche Ergebnisse liefern, könnte davon abhängen ob Kopierelision durchgeführt wird |
nimmt an dass Kopierelision immer
in konstanten Ausdrücken durchgeführt wird |
| CWG 2163 | C++14 |
Labels waren in
constexpr
Funktionen erlaubt
obwohl goto Anweisungen verboten sind |
Labels ebenfalls verboten |
| CWG 2268 | C++11 |
Kopieren/Verschieben einer Union mit mutable-Member war
durch die Lösung von CWG Issue 2004 verboten |
erlaubt wenn das Objekt innerhalb
des konstanten Ausdrucks erstellt wird |
| CWG 2278 | C++98 | die Lösung von CWG Issue 2022 war nicht implementierbar |
nimmt an dass Kopierelision niemals
in konstanten Ausdrücken durchgeführt wird |
| CWG 2531 | C++11 |
eine nicht-inline Variable wurde inline
wenn sie mit constexpr neu deklariert wird |
die Variable wird
nicht inline |
- ↑ Es ist redundant, da es nicht mehr als eine Deklaration einer Variablenvorlage mit dem constexpr Spezifizierer geben kann.
Siehe auch
| constant expression | definiert einen Ausdruck , der zur Compilezeit ausgewertet werden kann |
consteval
specifier
(C++20)
|
spezifiziert, dass eine Funktion eine Immediate Function ist, d.h. jeder Aufruf der Funktion muss in einer Konstantenauswertung erfolgen |
constinit
specifier
(C++20)
|
stellt sicher, dass eine Variable eine statische Initialisierung hat, d.h. Nullinitialisierung und Konstanteninitialisierung |
|
C-Dokumentation
für
constexpr
|
|