Recherche…


Introduction

constexpr est un mot - clé qui peut être utilisé pour marquer la valeur d'une variable en tant qu'expression constante, une fonction potentiellement utilisable dans les expressions constantes ou (depuis C ++ 17) une instruction if n'ayant qu'une seule de ses branches sélectionnée pour être compilée.

Remarques

Le mot-clé constexpr été ajouté en C ++ 11 mais depuis quelques années depuis la publication du standard C ++ 11, tous les compilateurs principaux ne l'ont pas supporté. au moment de la publication du standard C ++ 11. Au moment de la publication de C ++ 14, tous les principaux compilateurs prennent en charge constexpr .

variables constexpr

Une variable déclarée constexpr est implicitement const et sa valeur peut être utilisée comme une expression constante.

Comparaison avec #define

Un constexpr est un remplacement de type sécurisé pour les expressions de compilation basées sur #define . Avec constexpr l'expression évaluée à la compilation est remplacée par le résultat. Par exemple:

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

produira le code suivant:

cout << 12;

Une macro de compilation basée sur un pré-processeur serait différente. Considérer:

#define N 10 + 2

int main()
{
    cout << N;
}

produira:

cout << 10 + 2;

qui sera évidemment converti en cout << 10 + 2; . Cependant, le compilateur devrait faire plus de travail. En outre, cela crée un problème s'il n'est pas utilisé correctement.

Par exemple (avec #define ):

cout << N * 2;

formes:

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

Mais un constexpr pré-évalué donnerait correctement 24 .

Comparaison avec const

Une variable const est une variable qui a besoin de mémoire pour son stockage. Un constexpr ne le fait pas. Un constexpr produit une constante de temps de compilation, qui ne peut pas être modifiée. Vous pouvez soutenir que const peut également ne pas être modifié. Mais considérez:

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

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

Avec la plupart des compilateurs, la deuxième instruction échouera (peut fonctionner avec GCC, par exemple). La taille de tout tableau, comme vous le savez peut-être, doit être une expression constante (c’est-à-dire qu’il en résulte une valeur à la compilation). La deuxième variable size2 se voit attribuer une valeur qui est décidée à l'exécution (même si vous savez qu'il s'agit de 10 , pour le compilateur, ce n'est pas la compilation).

Cela signifie qu'un const peut ou peut ne pas être une constante constante de compilation. Vous ne pouvez pas garantir ou imposer qu'une valeur de const particulière est absolument à la compilation. Vous pouvez utiliser #define mais il a ses propres pièges.

Par conséquent, utilisez simplement:

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

    int arr[size];
}

Une expression constexpr doit donner une valeur à la compilation. Ainsi, vous ne pouvez pas utiliser:

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

Sauf si la fonction ( abs ) renvoie elle-même un constexpr .

Tous les types de base peuvent être initialisés avec constexpr .

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

Fait intéressant, et commodément, vous pouvez également utiliser auto :

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

fonctions constexpr

Une fonction déclarée constexpr est implicitement constexpr et les appels à une telle fonction peuvent générer des expressions constantes. Par exemple, la fonction suivante, si elle est appelée avec des arguments d'expression constante, produit également une expression constante:

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

Ainsi, le résultat de l'appel de fonction peut être utilisé en tant que tableau lié ou argument de modèle, ou pour initialiser une variable constexpr :

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

Notez que si vous supprimez constexpr de la spécification de type de retour de la fonction, l'affectation à S ne fonctionnera pas, car S est une variable constexpr et doit être constexpr à un const de compilation. De même, la taille du tableau ne sera pas non plus une expression constante, si la fonction Sum n'est pas constexpr .

Ce qui est intéressant constexpr fonctions constexpr , c'est que vous pouvez aussi l'utiliser comme des fonctions ordinaires:

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

Sum ne sera plus une fonction constexpr , elle sera compilée en tant que fonction ordinaire, en prenant des arguments variables (non constants) et en renvoyant une valeur non constante. Vous n'avez pas besoin d'écrire deux fonctions.

Cela signifie également que si vous essayez d'attribuer un tel appel à une variable non-const, il ne sera pas compilé:

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

La raison en est simple: une constexpr doit être attribuée à constexpr . Cependant, l'appel de fonction ci-dessus fait de Sum un non- constexpr (la valeur R est non-const, mais la valeur L se déclare constexpr ).


La fonction constexpr doit également renvoyer une constante à la compilation. Ce qui suit ne compilera pas:

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

Parce que a1 est une variable non-constexpr et interdit à la fonction d'être une véritable fonction constexpr . Le rendre constexpr et lui assigner a va également ne pas fonctionner - puisque la valeur d' a paramètre (paramètre entrant) n'est toujours pas connue:

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

De plus, la suite ne compilera pas non plus:

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

Puisque abs(a) n'est pas une expression constante (même abs(10) ne fonctionnera pas, puisque abs ne renvoie pas de constexpr int !

Et ça?

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

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

Nous avons conçu notre propre fonction Abs qui est un constexpr , et le corps d' Abs ne constexpr pas non plus la règle. En outre, sur le site d’appel (à l’intérieur de la Sum ), l’expression donne lieu à une constexpr . Par conséquent, l'appel à la Sum(-10, 20) sera une expression constante à la compilation qui donnera 30 .

Static si déclaration

C ++ 17

L' if constexpr peut être utilisée pour compiler de manière conditionnelle du code. La condition doit être une expression constante. La branche non sélectionnée est supprimée. Une instruction ignorée à l'intérieur d'un modèle n'est pas instanciée. Par exemple:

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
}

De plus, les variables et les fonctions qui ne sont utilisées que dans des instructions ignorées ne sont pas obligatoirement définies et les instructions de return ignorées ne sont pas utilisées pour la déduction de type retour de fonction.

if constexpr est distinct de #ifdef . #ifdef compile conditionnellement le code, mais uniquement sur la base de conditions pouvant être évaluées au moment du prétraitement. Par exemple, #ifdef n'a pas pu être utilisé pour compiler conditionnellement du code en fonction de la valeur d'un paramètre de modèle. Par contre, if constexpr ne peut pas être utilisé pour écarter un code syntaxiquement invalide, alors #ifdef peut.

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow