Inspiré par cette réponse , j'ai essayé de copier et coller (et d'ajouter des tests dans main()
) ce code:
template<typename T>
std::Tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
}
int main()
{
auto [x, y] = foo("");
std::cout << x << " " << y;
}
C'est très simple - si T
est déduit comme int
, nous voulons retourner un Tuple de [a, 0.0]
. Si T
est déduit comme double
, nous voulons retourner un Tuple de [0, a]
. Sinon, nous voulons retourner [0, 0.0]
.
Comme vous pouvez le voir, dans la fonction main()
, j'appelle foo
avec l'argument const char*
, Qui devrait résulte en x
et y
étant 0
. C'est pas le cas.
En essayant de le compiler, j'ai rencontré une étrange erreur:
erreur: impossible de convertir "
{0, a}
" de "<brace-enclosed initializer list>
" en "std::Tuple<int, double>
"
Et j'étais comme quoi?. Pourquoi diable voudrais-je cela ... J'ai spécifiquement utilisé std::is_same
Pour activer return {0, a}
uniquement lorsque le type de a
est déduit comme double
.
J'ai donc rapidement couru vers cppreference sur if-constexpr. Au bas de la page, au-dessus Notes , nous pouvons voir cet extrait de code:
extern int x; // no definition of x required
int f() {
if constexpr (true)
return 0;
else if (x)
return x;
else
return -x;
}
Je me suis dit ouais ..? Je ne peux pas vraiment voir ce qui ne va pas avec le code d'origine. Ils utilisent la même syntaxe et la même sémantique ....
Mais j'étais curieux. J'étais curieux de savoir si quelque chose d'étrange (à ce moment-là) pouvait résoudre ce problème, j'ai donc changé le code d'origine en:
template<typename T>
std::Tuple<int, double> foo(T a) {
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else if constexpr (std::is_same_v<double, T>) // notice the additional constexpr here
return {0, a};
else
return {0, 0.0};
}
int main()
{
auto [x, y] = foo("");
std::cout << x << " " << y;
}
Et voilà! Le code a été compilé et exécuté comme prévu. Donc, ma question est - Faut-il mettre constexpr
après chaque if
instruction dans if-else
Instruction dans ce genre de situations? Ou est-ce juste mon compilateur? J'utilise GCC 7.3.
Avons-nous besoin de mettre constexpr après chaque instruction if dans le bloc if-else dans ce genre de situations?
Oui. Le bloc else-if1 est un mensonge :), il n'y a que des blocs1 et sinon des blocs1. Voici comment votre code est vu par le compilateur:
if constexpr (std::is_same_v<int, T>)
return {a, 0.0};
else // {
if (std::is_same_v<double, T>)
return {0, a};
else
return {0, 0.0};
// }
else if (/*...*/)
n'est qu'une convention de formatage que tout le monde utilise. En tant que tel, vous pouvez clairement voir que le second constexpr
est nécessaire.
1: "bloc" n'est pas la terminologie correcte. if est une instruction (avec une partie else facultative). Un bloc est { /*...*/ }
.