Erläuterung
Einige Compiler (insbesondere GCC) verwenden eine höhere Genauigkeit, wenn Ausdrücke zur Kompilierungszeit ausgewertet werden. Wenn ein Ausdruck nur von konstanten Eingaben und Literalen abhängt, kann er zur Kompilierungszeit ausgewertet werden, auch wenn der Ausdruck keiner constexpr-Variablen zugewiesen ist. Ob dies geschieht oder nicht, hängt ab von:
- Die Komplexität des Ausdrucks
- Der Schwellenwert, den der Compiler als Grenzwert verwendet, wenn versucht wird, eine Auswertung der Kompilierungszeit durchzuführen
- Andere Heuristiken, die in besonderen Fällen verwendet werden (z. B. wenn Clang Elides-Schleifen)
Wenn ein Ausdruck wie im ersten Fall explizit angegeben wird, weist er eine geringere Komplexität auf, und der Compiler wird ihn wahrscheinlich zur Kompilierungszeit auswerten.
Wenn eine Funktion als inline markiert ist, wird sie vom Compiler eher zur Kompilierungszeit ausgewertet, da Inline-Funktionen den Schwellenwert erhöhen, bei dem die Auswertung erfolgen kann.
Höhere Optimierungsstufen erhöhen auch diesen Schwellenwert, wie im Beispiel -Ofast, bei dem alle Ausdrücke aufgrund der Bewertung der Kompilierungszeit mit höherer Genauigkeit auf gcc als wahr ausgewertet werden.
Wir können dieses Verhalten hier im Compiler-Explorer beobachten. Bei der Kompilierung mit -O1 wird zur Kompilierungszeit nur die inline markierte Funktion ausgewertet, bei -O3 werden beide Funktionen zur Kompilierungszeit ausgewertet.
NB: In den Compiler-Explorer-Beispielen verwende ich printfstattdessen iostream, da dies die Komplexität der Hauptfunktion verringert und den Effekt sichtbarer macht.
Dies inlinehat keinen Einfluss auf die Laufzeitauswertung
Wir können sicherstellen, dass keiner der Ausdrücke zur Kompilierungszeit ausgewertet wird, indem wir den Wert von der Standardeingabe erhalten. Wenn wir dies tun, geben alle drei Ausdrücke false zurück, wie hier gezeigt: 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; // false
std::cout << (is_cube(value)) << std::endl; // false
std::cout << (is_cube_inline(value)) << std::endl; // false
}
Im Gegensatz zu diesem Beispiel , in dem wir dieselben Compilereinstellungen verwenden, aber den Wert zur Kompilierungszeit angeben, führt dies zu einer genaueren Auswertung der Kompilierungszeit.