Consider the following definition:
template<int n> struct Foo;
template<> struct Foo<1> { void fn1(); };
template<> struct Foo<2> { void fn2(); };
Foo<1> has a member function fn1 and similarly Foo<2> has fn2. We can use these functions, selecting the appropriate function to call using an if constexpr expression:
template<int n>
void test_template() {
Foo<n> foo;
if constexpr (n==1) {
foo.fn1();
} else {
foo.fn2();
}
}
template void test_template<1>(); //Interested in `Foo<1>`
This works perfectly on latest Clang, GCC, and MSVC.
We can think about doing functionally the same thing, but with a constexpr expression:
constexpr int n = 1; //Interested in `Foo<1>`
void test_constexpr() {
Foo<n> foo;
if constexpr (n==1) {
foo.fn1();
} else {
foo.fn2();
}
}
This fails (on all three compilers)! Specifically, all compilers' errors show that they are attempting to compile foo.fn2().
Is this behavior correct? If so, why? It seems to me like the compilation should be similar, and that the second case should work too!
EDIT: several other questions have been asked about if constexpr in the context of template instantiations (see comments). However, this is specifically about if constexpr without templates. Indeed, the template version above works as I'd expect.
According to the C++ documentation:
If the value is
true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
However, it also says:
Outside a template, a discarded statement is fully checked.
if constexpris not a substitute for the#ifpreprocessing directive
The question is why this should be the case?
(Tagging this C++17, since if constexpr is a C++17 feature, though of course I am actually using C++20, and soon C++23 . . .)