Search code examples
c++c++20constexprif-constexpr

Avoid evaluating if-constexpr branch not taken


The following code fails to compile with the error no member named 'foo' in 'B' despite that only being an issue within a context that should be discarded at compile time.

#include <type_traits>

struct A {
    int foo() {
        return 1;
    }
};

struct B {
    int bar() {
        return 2;
    }
};

static constexpr bool TEST = false;
using T = std::conditional_t<TEST, A, B>;

int main() {
    T t{};
    if constexpr (TEST) {
        return t.foo();
    } else {
        return t.bar();
    }
}

What can I do to enable code like this? If I were to replace the constexpr with preprocessor macros this would likely work just fine, no?


Solution

  • https://en.cppreference.com/w/cpp/language/if has this to say about your situation:

    Outside a template, a discarded statement is fully checked

    This suggests that you can stick it into a template to make it work:

    template <typename U=T> int myMain()
    {
        U t{};
        if constexpr (TEST) {
            return t.foo();
        } else {
            return t.bar();
        }
    }
    
    int main() {
        return myMain();
    }
    

    Note: the stuff must actually depend on a template parameter; if you just keep the T t{};, that variable isn't really templated and the compiler will, again, just complain again. So, I had to provide a little workaround -- from the compiler's perspective, I could pass any U, so it has no clue what the t will be, and thus it will work.

    cppreference actually explains it as

    If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated.

    However, their explanation of "value-dependent" is written in some language that seems to use English words, but doesn't convey much in terms of meaning. So, I'll go with my intuitive explanation plus the part "the discarded statement is not instantiated" from the above quote, and go to bed without a headache.