Considérez le programme suivant:
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
return -1;
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
Il imprime -1
lors de l'exécution (wandbox).
Cependant, si je crée la fonction throw
lorsqu'elle est évaluée au moment de la compilation ::
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
throw -1; // <----------------------- Changed line
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
il compile bien et sort 1 (wandbox). Pourquoi n'ai-je pas obtenu un échec de compilation à la place?
L'évaluation constante n'est-elle pas amusante?
Il y a quelques endroits dans la langue où nous essayons pour faire une évaluation constante et si qui échoue, nous retombons sur une évaluation non constante. L'initialisation statique en est un, l'initialisation d'entiers constants en est un autre.
Que se passe-t-il avec:
int const i = f();
est que cette pourrait être évaluation constante, mais elle ne doit pas nécessairement l'être. Parce que (non - constexpr
) des entiers constants peuvent toujours être utilisés comme expressions constantes, s'ils remplissent toutes les autres conditions, nous devons essayer. Par exemple:
const int n = 42; // const, not constexpr
std::array<int, n> arr; // n is a constant expression, this is ok
Essayez donc de le faire - nous appelons f()
comme expression constante. Dans ce contexte, std::is_constant_evaluated()
est true
, donc nous avons frappé la branche avec le throw
et finissons par échouer. Impossible de throw
pendant une évaluation constante, donc notre évaluation constante échoue.
Mais ensuite, nous retombons, et nous essayons à nouveau - cette fois en appelant f()
en tant qu'expression non constante (c'est-à-dire std::is_constant_evaluated()
est false
). Ce chemin réussit, nous donnant 1
, Donc i
est initialisé avec la valeur 1
. Mais notamment, i
est pas une expression constante à ce stade. Une static_assert(i == 1)
suivante serait mal formée car l'initialiseur de i
était pas une expression constante! Même si le chemin d'initialisation non constant arrive (sinon) à satisfaire entièrement les exigences d'une expression constante.
Notez que si nous avons essayé:
constexpr int i = f();
Cela aurait échoué car nous ne pouvons pas revenir à l'initialisation non constante.