Suche…


Einführung

constexpr ist ein Schlüsselwort , das verwendet werden kann, um den Wert einer Variablen als konstanten Ausdruck zu kennzeichnen, eine Funktion, die möglicherweise in konstanten Ausdrücken verwendet werden kann, oder (seit C ++ 17) eine if-Anweisung , bei der nur einer ihrer Zweige zum Kompilieren ausgewählt wurde.

Bemerkungen

Das Schlüsselwort constexpr wurde in C ++ 11 hinzugefügt, aber seit der Veröffentlichung des C ++ 11-Standards wurde es nicht von allen großen Compilern unterstützt. zu der Zeit, als der C ++ 11-Standard veröffentlicht wurde. Zum Zeitpunkt der Veröffentlichung von C ++ 14 unterstützen alle großen Compiler constexpr .

Constexpr-Variablen

Eine deklarierte constexpr ist implizit const und ihr Wert kann als konstanter Ausdruck verwendet werden.

Vergleich mit #define

Ein constexpr ist typsichere Ersatz für #define basierte Kompilierung-Ausdrücke. Mit constexpr der zur Kompilierzeit ausgewertete Ausdruck durch das Ergebnis ersetzt. Zum Beispiel:

C ++ 11
int main()
{
   constexpr int N = 10 + 2;
   cout << N;
}

erzeugt den folgenden Code:

cout << 12;

Ein vorprozessorgestütztes Kompilierungszeitmakro würde sich unterscheiden. Erwägen:

#define N 10 + 2

int main()
{
    cout << N;
}

wird herstellen:

cout << 10 + 2;

das wird offensichtlich in cout << 10 + 2; . Der Compiler müsste jedoch mehr Arbeit erledigen. Es wird auch ein Problem erstellt, wenn es nicht korrekt verwendet wird.

Zum Beispiel (mit #define ):

cout << N * 2;

Formen:

cout << 10 + 2 * 2; // 14

Ein vorher ausgewertetes constexpr würde jedoch 24 .

Vergleich mit const

Eine const Variable ist eine Variable, die zum Speichern Speicher benötigt. Ein constexpr nicht. Ein constexpr erzeugt eine Kompilierungszeitkonstante, die nicht geändert werden kann. Sie können argumentieren, dass const auch nicht geändert werden darf. Aber bedenken Sie:

int main()
{
   const int size1 = 10;
   const int size2 = abs(10);

   int arr_one[size1]; 
   int arr_two[size2]; 
}

Bei den meisten Compilern schlägt die zweite Anweisung fehl (funktioniert beispielsweise mit GCC). Die Größe eines Arrays muss, wie Sie vielleicht wissen, ein konstanter Ausdruck sein (dh er führt zu einem Kompilierzeitwert). Der zweiten Variablen size2 wird ein Wert zugewiesen, der zur Laufzeit festgelegt wird (obwohl Sie wissen, dass es 10 , ist dies für den Compiler keine Kompilierzeit).

Dies bedeutet, dass ein const eine echte Konstante für die Kompilierungszeit sein kann oder nicht. Sie können nicht garantieren oder erzwingen, dass ein bestimmter const Wert die Kompilierungszeit ist. Sie können #define , hat aber eigene Fallstricke.

Verwenden Sie dazu einfach:

C ++ 11
int main()
{
    constexpr int size = 10;

    int arr[size];
}

Ein constexpr Ausdruck muss zu einem Kompilierungszeitwert ausgewertet werden. Daher können Sie nicht verwenden:

C ++ 11
constexpr int size = abs(10);

Es sei denn, die Funktion ( abs ) constexpr selbst ein constexpr .

Alle constexpr können mit constexpr initialisiert constexpr .

C ++ 11
constexpr bool FailFatal = true;
constexpr float PI = 3.14f;
constexpr char* site= "StackOverflow";

Interessanterweise und bequemerweise können Sie auch auto :

C ++ 11
constexpr auto domain = ".COM";  // const char * const domain = ".COM"
constexpr auto PI = 3.14;        // constexpr double

Constexpr-Funktionen

Eine Funktion, die als constexpr deklariert constexpr ist implizit inline und Aufrufe einer solchen Funktion führen möglicherweise zu konstanten Ausdrücken. Wenn die folgende Funktion beispielsweise mit Argumenten für konstante Ausdrücke aufgerufen wird, ergibt sich auch ein konstanter Ausdruck:

C ++ 11
constexpr int Sum(int a, int b)
{
    return a + b;
}

Daher kann das Ergebnis des Funktionsaufrufs als Array-gebundenes oder Template-Argument verwendet werden oder eine constexpr Variable initialisieren:

C ++ 11
int main()
{
    constexpr int S = Sum(10,20);
   
    int Array[S];
    int Array2[Sum(20,30)]; // 50 array size, compile time
}

Wenn Sie constexpr aus der Rückgabetypspezifikation der Funktion entfernen, funktioniert die Zuweisung an S nicht, da S eine constexpr Variable ist und eine constexpr zur Kompilierzeit zugewiesen werden muss. In ähnlicher Weise ist auch die Größe des Arrays kein Konstantenausdruck, wenn die Funktion Sum nicht constexpr .

Interessant an den constexpr Funktionen ist, dass Sie sie auch wie gewöhnliche Funktionen verwenden können:

C ++ 11
int a = 20;
auto sum = Sum(a, abs(-20));

Sum ist jetzt keine constexpr Funktion, sondern wird als gewöhnliche Funktion kompiliert, wobei variable (nicht konstante) Argumente verwendet werden und ein nicht konstanter Wert zurückgegeben wird. Sie müssen nicht zwei Funktionen schreiben.

Das bedeutet auch, dass wenn Sie versuchen, einen solchen Aufruf einer Nicht-const-Variablen zuzuweisen, diese nicht kompiliert wird:

C ++ 11
int a = 20;
constexpr auto sum = Sum(a, abs(-20));

Der Grund ist einfach: constexpr muss nur eine Kompilierungszeitkonstante zugewiesen werden. Der obige Funktionsaufruf macht Sum einem nicht- constexpr (R-Wert ist nicht-const, aber der L-Wert deklariert sich selbst zu constexpr ).


Die Funktion constexpr muss auch eine Konstante für die Kompilierungszeit zurückgeben. Folgendes wird nicht kompilieren:

C ++ 11
constexpr int Sum(int a, int b)
{
    int a1 = a;     // ERROR
    return a + b;
}

Weil a1 eine Nicht-Constexpr- Variable ist und verhindert, dass die Funktion eine echte constexpr Funktion ist. So dass es constexpr und Zuweisen a auch nicht - da Wert a (incoming Parameter) noch noch nicht bekannt ist:

C ++ 11
constexpr int Sum(int a, int b)
{
   constexpr int a1 = a;     // ERROR
   ..

Außerdem wird Folgendes nicht kompiliert:

C ++ 11
constexpr int Sum(int a, int b)
{
   return abs(a) + b; // or abs(a) + abs(b)
}

Da abs(a) kein konstanter Ausdruck ist (auch abs(10) funktioniert nicht, da abs kein constexpr int !

Was ist damit?

C ++ 11
constexpr int Abs(int v)
{
    return v >= 0 ? v : -v;
}

constexpr int Sum(int a, int b)
{
    return Abs(a) + b;
}

Wir haben unsere eigene Abs Funktion entwickelt, die ein constexpr , und der Körper von Abs constexpr auch keine Regel. Auch an der Aufrufstelle (innerhalb von Sum ) wird der Ausdruck zu einem constexpr ausgewertet. Daher ist der Aufruf von Sum(-10, 20) ein konstanter Ausdruck der Kompilierungszeit, der sich zu 30 ergibt.

Statische if-Anweisung

C ++ 17

Die if constexpr Anweisung kann verwendet werden, um Code bedingt zu kompilieren. Die Bedingung muss ein konstanter Ausdruck sein. Der nicht ausgewählte Zweig wird verworfen. Eine verworfene Anweisung in einer Vorlage wird nicht instanziiert. Zum Beispiel:

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

Außerdem müssen Variablen und Funktionen, die nur in verworfenen Anweisungen verwendet werden, nicht definiert werden, und verworfene return werden nicht für die Ableitung von Funktionstypen verwendet.

if constexpr von #ifdef . #ifdef kompiliert Code bedingt, jedoch nur basierend auf Bedingungen, die zum Zeitpunkt der Vorverarbeitung ausgewertet werden können. Beispielsweise kann #ifdef nicht verwendet werden, um Code abhängig vom Wert eines Vorlagenparameters bedingt zu kompilieren. if constexpr nicht dazu verwendet werden kann, syntaktisch ungültigen Code zu verwerfen, kann dies mit #ifdef .

if constexpr(false) {
    foobar;  // error; foobar has not been declared
    std::vector<int> v("hello, world");  // error; no matching constructor
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow