Namespaces
Variants

constexpr specifier (since C++11)

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

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:

(bis C++26)
(seit C++26)

  • Es besitzt konstante Destruktion, was bedeutet, dass eine der folgenden Bedingungen erfüllt sein muss:
  • Es ist nicht vom Klassentyp oder (möglicherweise mehrdimensionalem) Array davon.
  • Es ist vom Klassentyp mit einem constexpr Destruktor oder (möglicherweise mehrdimensionalem) Array davon, und für einen hypothetischen Ausdruck e , dessen einzige Wirkung die Zerstörung des Objekts ist, würde e ein Core Constant Expression sein, wenn die Lebensdauer des Objekts und seiner nicht-mutablen Unterobjekte (aber nicht seiner mutablen Unterobjekte) als innerhalb von e beginnend betrachtet würde.

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)
  • Sein Rückgabetyp (falls vorhanden) ist ein literal type .
  • Jeder seiner Parametertypen ist ein literal type.
(bis C++23)
(seit C++20)
(bis C++14)
  • Sein Funktionsrumpf ist = default , = delete , oder ein zusammengesetzter Anweisungsblock, der (bis C++20) folgendes nicht enthält :
(bis C++20)
  • Definitionen von Variablen nicht-literaler Typen
  • Definitionen von Variablen mit statischer oder Thread- Speicherdauer
(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:

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:

  • Sein Funktionsrumpf ist = delete oder erfüllt die folgenden zusätzlichen Anforderungen:
  • Wenn die Klasse eine Union mit Variant-Mitgliedern ist, wird genau eines davon initialisiert.
  • Wenn die Klasse eine union-ähnliche Klasse ist, aber keine Union, wird für jedes ihrer anonymen Union-Mitglieder mit Variant-Mitgliedern genau eines davon initialisiert.
  • Jedes nicht-variante nicht-statische Datenmitglied und Basisklassen-Teilobjekt wird initialisiert.
(bis C++20)
  • Wenn der Konstruktor ein delegierender Konstruktor ist, ist der Zielkonstruktor ein constexpr -Konstruktor.
  • Wenn der Konstruktor ein nicht-delegierender Konstruktor ist, ist jeder Konstruktor, der zur Initialisierung nicht-statischer Datenmitglieder und Basisklassen-Teilobjekte ausgewählt wird, ein constexpr -Konstruktor.
(bis C++23)

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:

  • Für jedes Unterobjekt vom Klassentyp oder (möglicherweise mehrdimensionales) Array davon muss dieser Klassentyp einen constexpr -Destruktor besitzen.
(bis C++23)
  • Die Klasse darf keine virtuelle Basisklasse besitzen.
(seit C++20)

Hinweise

Da der noexcept Operator für einen konstanten Ausdruck immer true zurückgibt, kann er verwendet werden, um zu prüfen, ob ein bestimmter Aufruf einer constexpr-Funktion den Zweig des konstanten Ausdrucks nimmt:

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

constexpr

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
  1. 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