Explication
Certains compilateurs (notamment GCC) utilisent une précision plus élevée lors de l'évaluation des expressions au moment de la compilation. Si une expression dépend uniquement d'entrées et de littéraux constants, elle peut être évaluée au moment de la compilation même si l'expression n'est pas affectée à une variable constexpr. Que cela se produise ou non dépend de:
- La complexité de l'expression
- Le seuil que le compilateur utilise comme seuil lors de la tentative d'exécution de l'évaluation du temps de compilation
- Autres heuristiques utilisées dans des cas particuliers (comme lorsque le clang élide les boucles)
Si une expression est explicitement fournie, comme dans le premier cas, elle a une complexité moindre et le compilateur est susceptible de l'évaluer au moment de la compilation.
De même, si une fonction est marquée en ligne, le compilateur est plus susceptible de l'évaluer au moment de la compilation, car les fonctions en ligne élèvent le seuil auquel l'évaluation peut avoir lieu.
Des niveaux d'optimisation plus élevés augmentent également ce seuil, comme dans l'exemple -Ofast, où toutes les expressions sont évaluées à true sur gcc en raison d'une évaluation plus précise au moment de la compilation.
Nous pouvons observer ce comportement ici sur l'explorateur du compilateur. Lorsqu'elle est compilée avec -O1, seule la fonction marquée en ligne est évaluée au moment de la compilation, mais à -O3 les deux fonctions sont évaluées au moment de la compilation.
NB: Dans les exemples du compilateur-explorateur, j'utilise à la printfplace iostream car il réduit la complexité de la fonction principale, rendant l'effet plus visible.
Démontrer que cela inlinen'affecte pas l'évaluation d'exécution
Nous pouvons nous assurer qu'aucune des expressions n'est évaluée au moment de la compilation en obtenant la valeur de l'entrée standard, et lorsque nous faisons cela, les 3 expressions renvoient false comme démontré ici: 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;
}
Contrairement à cet exemple , où nous utilisons les mêmes paramètres du compilateur mais fournissons la valeur au moment de la compilation, ce qui entraîne une évaluation plus précise au moment de la compilation.