Freigeben über


constexpr (C++)

Das Schlüsselwort constexpr wurde in C++11 eingeführt und in C++14 verbessert. Es bedeutet konstanter Ausdruck. Wie const kann beispielsweise auf Variablen angewendet werden: Ein Compilerfehler wird ausgelöst, wenn ein Code versucht, den Wert zu ändern. Anders als const, constexpr kann auch auf Funktionen und Klassenkonstruktoren angewendet werden. constexpr gibt an, dass der Wert oder Rückgabewert konstant ist und nach Möglichkeit zur Kompilierzeit berechnet wird.

Ein ganzzahliger constexpr-Wert kann verwendet werden, wenn eine ganzzahlige const Konstante erforderlich ist, wie z. B. in Vorlagenargumenten und Arraydeklarationen. Und wenn ein Wert zur Kompilierungszeit anstelle der Laufzeit berechnet wird, hilft es Ihrem Programm, schneller zu laufen und weniger Arbeitsspeicher zu verwenden.

Um die Komplexität von konstanten Berechnungen zur Kompilierzeit und ihre potenziellen Auswirkungen auf die Kompilierungszeit zu begrenzen, verlangt der C++14-Standard, dass es sich bei den Typen in konstanten Ausdrücken um Literaltypen handelt .

Syntax

constexprLiteraltypBezeichner=konstantenausdruck;
constexprLiteraltyp{Bezeichnerkonstantenausdruck};
constexprBezeichner des Literaltyps(params);
constexprctor(params);

Parameter

params
Einen oder mehrere Parameter, bei denen es sich jeweils um einen Literaltyp und einen konstanten Ausdruck handeln muss.

Rückgabewert

Eine constexpr Variable oder Funktion muss einen Literaltypzurückgeben.

constexpr-Variablen

Der Hauptunterschied zwischen const und constexpr Variablen besteht darin, dass die Initialisierung einer const Variablen bis zur Laufzeit verzögert werden kann. Eine constexpr Variable muss zur Kompilierungszeit initialisiert werden. Alle constexpr Variablen sind const.

  • Eine Variable kann mit constexpr deklariert werden, wenn sie über einen Literaltyp verfügt und initialisiert wird. Wenn die Initialisierung von einem Konstruktor ausgeführt wird, muss der Konstruktor als constexprdeklariert werden.

  • Ein Verweis kann als constexpr deklariert werden, wenn diese beiden Bedingungen erfüllt sind: Das referenzierte Objekt wird durch einen konstanten Ausdruck initialisiert, und alle impliziten Umwandlungen, die während der Initialisierung aufgerufen werden, sind ebenfalls konstante Ausdrücke.

  • Alle Deklarationen einer constexpr Variablen oder Funktion müssen über den constexpr Bezeichner verfügen.

constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression

constexpr -Funktionen

Eine constexpr Funktion ist eine Funktion, deren Rückgabewert zur Kompilierungszeit bei Verwendung von Code erforderlich ist. Der Verbrauch von Code erfordert den Rückgabewert zur Kompilierungszeit, um eine constexpr Variable zu initialisieren oder ein Nicht-Typ-Vorlagenargument bereitzustellen. Wenn es sich bei den Argumenten um constexpr Werte handelt, erzeugt eine constexpr Funktion eine Kompilierzeitkonstante. Bei einem Aufruf mit Nicht-constexpr-Argumenten, oder wenn der Wert nicht zum Zeitpunkt der Kompilierung erforderlich ist, wird ein Wert zur Laufzeit wie eine reguläre Funktion erzeugt. (Durch dieses duale Verhalten müssen Sie keine constexpr- und Nicht-constexpr-Versionen derselben Funktion schreiben.)

Eine constexpr Funktion oder ein Konstruktor ist implizit inline.

Für constexpr-Funktionen gelten die folgenden Regeln:

  • Eine constexpr-Funktion muss nur Literaltypen akzeptieren und zurückgeben.

  • Eine constexpr-Funktion kann rekursiv sein.

  • Vor C++20 kann eine constexpr Funktion nicht virtuell sein, und ein Konstruktor kann nicht als constexpr definiert werden, wie wenn die einschließende Klasse über virtuelle Basisklassen verfügt. In C++20 und höher kann eine constexpr Funktion virtuell sein. Visual Studio 2019 Version 16.10 und höher unterstützen constexpr virtuelle Funktionen, wenn Sie die /std:c++20 Compileroption oder höher angeben.

  • Der Text kann als = default oder = delete definiert werden.

  • Der Textkörper kann keine goto Anweisungen oder try Blöcke enthalten.

  • Eine explizite Spezialisierung einer Nicht-constexpr-Vorlage kann als constexpr deklariert werden:

  • Eine explizite Spezialisierung einer constexpr Vorlage muss nicht auch constexpr sein:

Die folgenden Regeln gelten für constexpr Funktionen in Visual Studio 2017 und höher:

  • Sie kann if und switch Anweisungen sowie alle Schleifenanweisungen enthalten, einschließlich for, bereichsbasiert for, while und do-while.

  • Sie kann lokale Variablendeklarationen enthalten, die Variable muss jedoch initialisiert werden. Sie muss ein Literaltyp sein und darf nicht static oder thread-lokal sein. Die lokal deklarierte Variable muss nicht const sein und kann mutieren.

  • Eine constexpr Nicht-Member-Funktionstatic muss nicht implizit constsein.

constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

Tipp

Im Visual Studio-Debugger können Sie beim Debuggen eines nicht optimierten Debugbuilds feststellen, ob eine constexpr Funktion zur Kompilierungszeit ausgewertet wird, indem Sie einen Haltepunkt darin einfügen. Wenn der Haltepunkt erreicht wird, wurde die Funktion zur Laufzeit aufgerufen. Wenn nicht, wurde die Funktion während der Kompilierung aufgerufen.

extern constexpr

Die Compileroption /Zc:externConstexpr bewirkt, dass der Compiler externe Verknüpfungen auf Variablen anwendet, die mithilfe von extern constexprdeklariert werden. In früheren Versionen von Visual Studio wendet Visual Studio entweder standardmäßig oder wenn /Zc:externConstexpr- angegeben ist, die interne Verknüpfung auf constexpr Variablen an, auch wenn das extern Schlüsselwort verwendet wird. Die Option "/Zc:externConstexpr" ist ab Visual Studio 2017 Update 15.6 verfügbar und ist standardmäßig deaktiviert. Die Option "/permissive" aktiviert /Zc:externConstexpr nicht.

Beispiel

Das folgende Beispiel zeigt constexpr-Variablen, -Funktionen und einen benutzerdefinierten Typ. In der letzten Anweisung in main() ist die constexpr Memberfunktion GetValue() ein Laufzeitaufruf, da der Wert zur Kompilierungszeit nicht bekannt sein muss.

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp2(x * x, n / 2) :
        exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
    return N;
}

// Recursive constexpr function
constexpr int fac(int n)
{
    return n == 1 ? 1 : n * fac(n - 1);
}

// User-defined type
class Foo
{
public:
    constexpr explicit Foo(int i) : _i(i) {}
    constexpr int GetValue() const
    {
        return _i;
    }
private:
    int _i;
};

int main()
{
    // foo is const:
    constexpr Foo foo(5);
    // foo = Foo(6); //Error!

    // Compile time:
    constexpr float x = exp(5, 3);
    constexpr float y { exp(2, 5) };
    constexpr int val = foo.GetValue();
    constexpr int f5 = fac(5);
    const int nums[] { 1, 2, 3, 4 };
    const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

    // Run time:
    cout << "The value of foo is " << foo.GetValue() << endl;
}

Anforderungen

Visual Studio 2015 oder eine höhere Version.

Weitere Informationen

Deklarationen und Definitionen
const