web-dev-qa-db-fra.com

const vs constexpr sur les variables

Y a-t-il une différence entre les définitions suivantes?

const     double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;

Sinon, quel style est préféré en C++ 11?

254
fredoverflow

Je crois qu'il y a une différence. Renommons-les afin de pouvoir en parler plus facilement:

const     double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;

PI1 et PI2 sont tous deux constants, ce qui signifie que vous ne pouvez pas les modifier. Cependant niquementPI2 est une constante de compilation. Il doit être initialisé à la compilation. PI1 peut être initialisé à la compilation ou à l'exécution. De plus, niquementPI2 peut être utilisé dans un contexte nécessitant une constante au moment de la compilation. Par exemple:

constexpr double PI3 = PI1;  // error

mais:

constexpr double PI3 = PI2;  // ok

et:

static_assert(PI1 == 3.141592653589793, "");  // error

mais:

static_assert(PI2 == 3.141592653589793, "");  // ok

Pour ce que vous devriez utiliser? Utilisez ce qui répond à vos besoins. Voulez-vous vous assurer que vous avez une constante de temps de compilation qui peut être utilisée dans des contextes où une constante de temps de compilation est requise? Voulez-vous pouvoir l'initialiser avec un calcul effectué au moment de l'exécution? Etc.

293
Howard Hinnant

Aucune différence ici, mais cela importe quand vous avez un type qui a un constructeur.

struct S {
    constexpr S(int);
};

const S s0(0);
constexpr S s1(1);

s0 est une constante, mais elle ne promet pas d'être initialisée à la compilation. s1 est marqué constexpr, il s'agit donc d'une constante et, étant donné que le constructeur de S est également marqué constexpr, il sera initialisé à la compilation.

Cela importe surtout lorsque l'initialisation au moment de l'exécution prend beaucoup de temps et que vous souhaitez appliquer ce travail au compilateur, qui prend également beaucoup de temps, mais ne ralentit pas le temps d'exécution du programme compilé.

71
Pete Becker

constexpr indique une valeur constante et connue lors de la compilation.
const indique une valeur uniquement constante; il n'est pas obligatoire de savoir lors de la compilation.

int sz;
constexpr auto arraySize1 = sz;    // error! sz's value unknown at compilation
std::array<int, sz> data1;         // error! same problem

constexpr auto arraySize2 = 10;    // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

Notez que const n’offre pas la même garantie que constexpr car il n’est pas nécessaire d’initialiser les objets const avec des valeurs connues lors de la compilation.

int sz;
const auto arraySize = sz;       // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation

Tous les objets constexpr sont const, mais tous les objets const ne sont pas constexpr.

Si vous voulez que les compilateurs garantissent qu'une valeur a une valeur pouvant être utilisée dans des contextes nécessitant des constantes à la compilation, l'outil à atteindre est constexpr, pas const.

37
Ajay yadav

Une constante symbolique constexpr doit recevoir une valeur connue au moment de la compilation. Par exemple:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    constexpr int c2 = n+7;   // Error: we don’t know the value of c2
    // ...
}

Pour gérer les cas où la valeur d'une "variable" initialisée avec une valeur inconnue au moment de la compilation mais qui ne change jamais après l'initialisation, C++ propose une seconde forme de constante (a const). Par exemple:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    const int c2 = n+7; // OK, but don’t try to change the value of c2
    // ...
    c2 = 7; // error: c2 is a const
}

Ces "const variables" sont très courantes pour deux raisons:

  1. C++ 98 n'avait pas constexpr, donc les gens utilisaient const.
  2. L'élément de liste "Les variables" qui ne sont pas des expressions constantes (leur valeur n'est pas connue au moment de la compilation) mais qui ne changent pas de valeur après l'initialisation sont en elles-mêmes largement utiles.

Référence: "Programmation: principes et pratique utilisant le C++" de Stroustrup

14
Jnana