`if constexpr` with `template` arguments vs. with `constexpr` expressions

47 Views Asked by At

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 constexpr is not a substitute for the #if preprocessing directive

The question is why this should be the case?


(live example on gcc.godbolt)

(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 . . .)

0

There are 0 best solutions below