Spiegazione
Alcuni compilatori (in particolare GCC) usano una precisione maggiore quando valutano le espressioni in fase di compilazione. Se un'espressione dipende solo da input e letterali costanti, può essere valutata in fase di compilazione anche se l'espressione non è assegnata a una variabile constexpr. Se ciò si verifica o meno dipende da:
- La complessità dell'espressione
- La soglia utilizzata dal compilatore come interruzione quando tenta di eseguire la valutazione in fase di compilazione
- Altre euristiche utilizzate in casi speciali (come quando clang elides si ripete)
Se un'espressione viene fornita esplicitamente, come nel primo caso, ha una complessità inferiore ed è probabile che il compilatore la valuti in fase di compilazione.
Allo stesso modo, se una funzione è contrassegnata come inline, è più probabile che il compilatore la valuti in fase di compilazione perché le funzioni inline aumentano la soglia alla quale può verificarsi la valutazione.
Livelli di ottimizzazione più alti aumentano anche questa soglia, come nell'esempio -Ofast, dove tutte le espressioni restituiscono true su gcc a causa di una valutazione in fase di compilazione più precisa.
Possiamo osservare questo comportamento qui su Esplora risorse del compilatore. Quando viene compilato con -O1, solo la funzione contrassegnata come inline viene valutata in fase di compilazione, ma in -O3 entrambe le funzioni vengono valutate in fase di compilazione.
NB: Negli esempi compilatore-esploratore, utilizzo printfinvece iostream perché riduce la complessità della funzione principale, rendendo più visibile l'effetto.
Dimostrare che inlinenon influisce sulla valutazione del runtime
Possiamo garantire che nessuna delle espressioni venga valutata in fase di compilazione ottenendo il valore dall'input standard e, quando lo facciamo, tutte e 3 le espressioni restituiscono false come dimostrato qui: https://ideone.com/QZbv6X
#include <cmath>
#include <iostream>
bool is_cube(double r)
{
return floor(cbrt(r)) == cbrt(r);
}
bool inline is_cube_inline(double r)
{
return floor(cbrt(r)) == cbrt(r);
}
int main()
{
double value;
std::cin >> value;
std::cout << (floor(cbrt(value)) == cbrt(value)) << std::endl;
std::cout << (is_cube(value)) << std::endl;
std::cout << (is_cube_inline(value)) << std::endl;
}
Contrasto con questo esempio , in cui usiamo le stesse impostazioni del compilatore ma forniamo il valore in fase di compilazione, con conseguente valutazione in fase di compilazione più precisa.