const vs constexpr su variabili

C’è una differenza tra le seguenti definizioni?

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

In caso contrario, quale stile è preferito in C ++ 11?

Credo che ci sia una differenza. Rinominiamoli in modo che possiamo parlarne più facilmente:

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

Sia PI1 che PI2 sono costanti, ovvero non è ansible modificarli. Tuttavia solo PI2 è una costante in fase di compilazione. Deve essere inizializzato al momento della compilazione. PI1 può essere inizializzato in fase di compilazione o in fase di esecuzione. Inoltre, solo PI2 può essere utilizzato in un contesto che richiede una costante in fase di compilazione. Per esempio:

 constexpr double PI3 = PI1; // error 

ma:

 constexpr double PI3 = PI2; // ok 

e:

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

ma:

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

Per quanto dovresti usare? Usa quello che soddisfa le tue esigenze. Vuoi assicurarti di avere una costante di tempo di compilazione che possa essere utilizzata in contesti in cui è richiesta una costante in fase di compilazione? Vuoi essere in grado di inizializzarlo con un calcolo fatto in fase di esecuzione? Eccetera.

Nessuna differenza qui, ma importa quando hai un tipo che ha un costruttore.

 struct S { constexpr S(int); }; const S s0(0); constexpr S s1(1); 

s0 è una costante, ma non promette di essere inizializzata in fase di compilazione. s1 è marcato constexpr , quindi è una costante e, poiché il costruttore di S è anche marcato constexpr , sarà inizializzato in fase di compilazione.

Principalmente ciò conta quando l’inizializzazione in fase di esecuzione richiederebbe molto tempo e si desidera trasferire tale lavoro sul compilatore, dove è anche dispendioso in termini di tempo, ma non rallenta i tempi di esecuzione del programma compilato

constexpr indica un valore costante e noto durante la compilazione.
const indica un valore che è solo costante; non è obbligatorio sapere durante la compilazione.

 int sz; constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation std::array data1; // error! same problem constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant std::array data2; // fine, arraySize2 is constexpr 

Si noti che const non offre la stessa garanzia di constexpr, poiché gli oggetti const non devono essere inizializzati con valori noti durante la compilazione.

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

Tutti gli oggetti constexpr sono const, ma non tutti gli oggetti const sono constexpr.

Se si desidera che i compilatori garantiscano che una variabile abbia un valore che può essere utilizzato in contesti che richiedono costanti in fase di compilazione, lo strumento da raggiungere è constexpr, non const.

Una costante simbolica di constexpr deve avere un valore noto al momento della compilazione. Per esempio:

 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 // ... } 

Per gestire casi in cui il valore di una “variabile” inizializzata con un valore che non è noto in fase di compilazione ma non cambia mai dopo l’inizializzazione, C ++ offre una seconda forma di costante (a const ). Per esempio:

 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 } 

Tali “variabili const ” sono molto comuni per due motivi:

  1. C ++ 98 non aveva constexpr, quindi le persone usavano const .
  2. Elenca le voci “Variabili” che non sono espressioni costanti (il loro valore non è noto al momento della compilazione) ma non modificano i valori dopo l’inizializzazione sono di per sé ampiamente utili.

Riferimento: “Programming: Principles and Practice Using C ++” di Stroustrup