Zoeken…


Invoering

constexpr is een sleutelwoord dat kan worden gebruikt om de waarde van een variabele te markeren als een constante expressie, een functie die mogelijk bruikbaar is in constante expressies, of (sinds C ++ 17) een if-instructie waarbij slechts één van de vertakkingen is geselecteerd om te worden gecompileerd.

Opmerkingen

Het sleutelwoord constexpr is toegevoegd in C ++ 11, maar sinds de publicatie van de C ++ 11-standaard een paar jaar lang werd dit niet door alle grote compilers ondersteund. op het moment dat de C ++ 11-standaard werd gepubliceerd. Vanaf het moment van publicatie van C ++ 14 ondersteunen alle belangrijke compilers constexpr .

constexpr-variabelen

Een variabele die constexpr wordt constexpr is impliciet const en de waarde ervan kan als een constante uitdrukking worden gebruikt.

Vergelijking met #define

Een constexpr is een constexpr vervanging voor op #define gebaseerde compile-time expressies. Met constexpr de constexpr de compilatie geëvalueerde expressie vervangen door het resultaat. Bijvoorbeeld:

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

zal de volgende code produceren:

cout << 12;

Een op de processor gebaseerde compilatie-macro zou anders zijn. Overwegen:

#define N 10 + 2

int main()
{
    cout << N;
}

zal produceren:

cout << 10 + 2;

die uiteraard wordt geconverteerd naar cout << 10 + 2; . De compiler zou echter meer werk moeten doen. Het creëert ook een probleem als het niet correct wordt gebruikt.

Bijvoorbeeld (met #define ):

cout << N * 2;

vormen:

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

Maar een vooraf geëvalueerde constexpr zou correct 24 geven.

Vergelijking met const

Een const variabele is een variabele die geheugen nodig heeft voor de opslag ervan. Een constexpr doet dat niet. Een constexpr produceert compileertijdconstante, die niet kan worden gewijzigd. Je zou kunnen beweren dat const ook niet mag worden gewijzigd. Maar overweeg:

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

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

Bij de meeste compilers mislukt de tweede instructie (kan bijvoorbeeld met GCC werken). De grootte van elke array moet, zoals u misschien weet, een constante expressie zijn (dat wil zeggen resulteert in compilatie-tijdwaarde). Aan de tweede variabele size2 wordt een waarde toegewezen die tijdens runtime wordt bepaald (hoewel u weet dat het 10 , is het voor de compiler geen compilatie).

Dit betekent dat een const al dan niet een echte compilatie-tijdconstante kan zijn. U kunt niet garanderen of afdwingen dat een bepaalde const waarde absoluut compilatie is. U kunt #define maar het heeft zijn eigen valkuilen.

Gebruik daarom gewoon:

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

    int arr[size];
}

Een constexpr expressie moet de waarde compileren. U kunt dus niet gebruiken:

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

Tenzij de functie ( abs ) zelf een constexpr .

Alle basistypen kunnen worden geïnitialiseerd met constexpr .

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

Interessant en handig kunt u ook auto :

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

constexpr-functies

Een functie die constexpr wordt verklaard constexpr is impliciet inline en roept een dergelijke functie op die mogelijk constante expressies constexpr . De volgende functie levert bijvoorbeeld, indien aangeroepen met argumenten voor constante expressie, ook een constante expressie op:

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

Het resultaat van de functieaanroep kan dus worden gebruikt als een array-gebonden of een sjabloonargument, of om een constexpr variabele te initialiseren:

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

Merk op dat als u constexpr uit de specificatie van het constexpr van de functie verwijdert, toewijzing aan S niet zal werken, aangezien S een constexpr variabele is en een compile-time const moet krijgen. Evenzo zal de grootte van de array ook geen constante-expressie zijn, als de functie Sum niet constexpr .

Interessant aan constexpr functies is dat u het ook kunt gebruiken als gewone functies:

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

Sum zal nu geen constexpr functie zijn, het wordt gecompileerd als een gewone functie, waarbij variabele (niet-constante) argumenten worden gebruikt en niet-constante waarde wordt constexpr . U hoeft niet twee functies te schrijven.

Het betekent ook dat als u een dergelijke aanroep probeert toe te wijzen aan een niet-const variabele, deze niet zal compileren:

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

De reden is simpel: aan constexpr moet alleen een compilatie-tijdconstante worden toegewezen. De bovenstaande functieaanroep maakt Sum een niet- constexpr (R-waarde is niet-const, maar L-waarde verklaart zichzelf constexpr ).


De constexpr functie moet ook een compilatie-tijdconstante retourneren. Volgende compileert niet:

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

Omdat a1 een niet-constexpr- variabele is en verbiedt dat de functie een echte constexpr functie is. Daarom is constexpr en het toewijzen van a zal evenmin work - aangezien waarde van a (inkomend parameter) is nog steeds niet bekend:

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

Verder zullen de volgende ook niet compileren:

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

Omdat abs(a) geen constante uitdrukking is (zelfs abs(10) zal niet werken, aangezien abs geen constexpr int retourneert!

Hoe zit het met dit?

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

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

We hebben onze eigen Abs functie gemaakt, die een constexpr , en het lichaam van Abs breekt ook geen enkele regel. Op de oproepsite (in Sum ) wordt de uitdrukking ook geëvalueerd als een constexpr . Daarom zal de aanroep naar Sum(-10, 20) een compilatie-tijd constante expressie zijn die resulteert in 30 .

Statische if-verklaring

C ++ 17

De instructie if constexpr kan worden gebruikt om code voorwaardelijk te compileren. De voorwaarde moet een constante uitdrukking zijn. De vertakking die niet is geselecteerd, wordt verwijderd. Een weggegooide verklaring in een sjabloon wordt niet geïnstantieerd. Bijvoorbeeld:

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
}

Bovendien worden variabelen en functies die worden gebruikt ODR alleen binnen weggegooid verklaringen niet te worden gedefinieerd en weggegooid return verklaringen niet gebruikt functieretourneringstype aftrek.

if constexpr verschilt van #ifdef . #ifdef compileert voorwaardelijk code, maar alleen op basis van voorwaarden die tijdens de voorbewerking kunnen worden geëvalueerd. Afhankelijk van de waarde van een sjabloonparameter kan #ifdef bijvoorbeeld niet worden gebruikt om code voorwaardelijk te compileren. Aan de andere kant, if constexpr niet kan worden gebruikt om syntactisch ongeldige code weg te gooien, terwijl #ifdef kan.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow