Non credo che nessuna delle risposte chiarisca esattamente quali effetti collaterali ha, o in effetti, di cosa si tratta.
constexpre constallo spazio dei nomi / ambito dei file sono identici quando inizializzati con un valore letterale o un'espressione; ma con una funzione, constpuò essere inizializzato da qualsiasi funzione, ma constexprinizializzato da un non-constexpr (una funzione che non è contrassegnata con constexpr o un'espressione non constexpr) genererà un errore del compilatore. Entrambi constexpre constsono implicitamente un collegamento interno per le variabili (in realtà, non sopravvivono per arrivare allo stadio di collegamento se si compila -O1 e più forte, e staticnon impone al compilatore di emettere un simbolo di collegamento interno (locale) per consto constexprquando a -O1 o più forte; l'unica volta che lo fa è se prendi l'indirizzo della variabile conste constexprsarà un simbolo interno se non espresso con externieextern constexpr/const int i = 3;deve essere usato). Su una funzione, .constexprrende la funzione in modo permanente mai raggiungere lo stadio di collegamento (indipendentemente da externo inlinenella definizione o -O0 o -Oveloce), mentre constnon lo fa mai e statice ha inlinesolo questo effetto su -O1 e sopra. Quando una const/ constexprvariabile viene inizializzata da una o , o se la variabile non è un /constexpr funzione, il carico è sempre ottimizzato con qualsiasi flag di ottimizzazione, ma non è mai ottimizzato se la funzione è solo staticinlineconstconstexpr
Compilazione standard (-O0)
#include<iostream>
constexpr int multiply (int x, int y)
{
return x * y;
}
extern const int val = multiply(10,10);
int main () {
std::cout << val;
}
compila a
val:
.long 100 //extra external definition supplied due to extern
main:
push rbp
mov rbp, rsp
mov esi, 100 //substituted in as an immediate
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
__static_initialization_and_destruction_0(int, int):
.
.
.
però
#include<iostream>
const int multiply (int x, int y)
{
return x * y;
}
const int val = multiply(10,10); //constexpr is an error
int main () {
std::cout << val;
}
Compila per
multiply(int, int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-4]
imul eax, DWORD PTR [rbp-8]
pop rbp
ret
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR val[rip]
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
__static_initialization_and_destruction_0(int, int):
.
.
.
mov esi, 10
mov edi, 10
call multiply(int, int)
mov DWORD PTR val[rip], eax
Questo lo dimostra chiaramente constexpr provoca l'inizializzazione della const/constexprvariabile dell'ambito del file al momento della compilazione e non produce alcun simbolo globale, mentre il mancato utilizzo provoca l'inizializzazione primamain runtime.
Compilare usando -Ofast
Anche -Ofast non ottimizza il carico! https://godbolt.org/z/r-mhif , quindi è necessario constexpr
constexprle funzioni possono anche essere richiamate dall'interno di altre constexprfunzioni per lo stesso risultato. constexprsu una funzione impedisce anche l'uso di tutto ciò che non può essere fatto in fase di compilazione nella funzione; per esempio, una chiamata <<all'operatore sustd::cout .
constexpra block scope si comporta allo stesso modo in quanto produce un errore se inizializzato da una funzione non constexpr; il valore viene anche sostituito immediatamente.
Alla fine, il suo scopo principale è come la funzione inline di C, ma è efficace solo quando la funzione viene utilizzata per inizializzare le variabili dell'ambito dei file (che le funzioni non possono fare su C, ma possono su C ++ perché consente l'inizializzazione dinamica di file- variabili dell'ambito), tranne per il fatto che la funzione non può esportare un simbolo globale / locale anche sul linker, anche usando extern/static, che potresti usare inlinesu C; Le funzioni di assegnazione delle variabili a scopo di blocco possono essere integrate semplicemente usando un'ottimizzazione -O1 senza constexprsu C e C ++.
constexprcrea una costante di compilazione;constsignifica semplicemente che il valore non può essere modificato.