Bien que j'ai code utilisé comme ça avant, et il est clair que le compilateur a suffisamment d'informations pour travailler, je ne comprends pas vraiment pourquoi cette compile:Constante intégrale transmise par valeur, traitée comme constexpr?
template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}
int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}
exemple en direct: http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.
Semble fonctionner à la fois avec gcc et clang. Le fait est quea une conversion constexpr
à l'entier stocké, constexpr
les fonctions membres prennent implicitement l'objet lui-même comme argument, et par conséquent une telle fonction ne peut pas être utilisée dans un contexte constexpr
à moins que l'objet que nous appelons le membre fonctionne lui-même peut être traité comme constexpr
.
Ici, i
est un argument passé à foo
, et donc i
ne peut certainement pas être traité comme. Pourtant, c'est. Un exemple encore plus simple:
template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}
Cette compile aussi, tant que std::integral_constant<std::size_t, 0>{}
est passé à foo
. J'ai l'impression qu'il me manque quelque chose d'évident sur les règles constexpr
. Existe-t-il une exception pour les types sans état, ou autre chose? (ou, peut-être, un bug de compilateur dans deux compilateurs majeurs? Ce code semble fonctionner sur clang 5 et gcc 7.2). Edit: une réponse a été postée, mais je ne pense pas que ce soit suffisant. En particulier, compte tenu de la dernière définition de foo
, pourquoi:
foo(std::integral_constant<std::size_t, 0>{});
Compile, mais pas:
foo(0);
Les deux 0 et std::integral_constant<std::size_t, 0>{}
sont des expressions constantes.
Édition 2: Il semble que cela se résume au fait que l'appel d'une fonction membre constexpr
même sur un objet qui n'est pas une expression constante, peut lui-même être considéré comme une expression constante, tant que this
est inutilisé. Ceci est pris comme évident. Je ne considère pas cette évidence:
constexpr int foo(int x, int y) { return x; }
constexpr void bar(int y) { constexpr auto x = foo(0, y); }
Cela ne compile pas, parce que y
passé dans foo
n'est pas une expression constante. C'est être inutilisé n'a pas d'importance. Par conséquent, une réponse complète doit afficher une sorte de langage de la norme pour justifier le fait qu'une fonction membre constexpr
peut être utilisée comme une expression constante, même sur un objet d'expression non constante, tant que this
est inutilisé.
Fonctionne aussi sur Visual C++: https://godbolt.org/g/Cknxco – Justin
Semble échouer sur le compilateur intel: https://godbolt.org/g/wLc5dw – Justin
@Justin Bon catch bien que vu que c'est icc Je parie que c'est un autre bug sans rapport :-). –