jjcasmar
jjcasmar

Reputation: 1685

if constexpr block not compiling

I have a class that can inherit from an empty struct or from a struct with some members, depending on a bool. Using that same bool, I am adding an if constexpr block to access the members of the base class, but I am getting a compiler error

struct A{};
struct B{};
struct C{};

template <typename J0, typename J1>
struct HasFriction {
    constexpr static bool value = false;
};

template <> struct HasFriction<A,B> {
    constexpr static bool value = true;
};

template <bool> struct Friction { };
template <> struct Friction<true> { int value = 4; };

template <typename J0, typename J1>
struct MyStruct : public Friction<HasFriction<J0, J1>::value> {};

int main()
{
    if constexpr (HasFriction<A, C>::value) {
        MyStruct<A,C> f;
        return f.value;
    } else {
        MyStruct<A,C> no_f;
        return 0;
    }
}

Why is this not working, and how should I fix it?

Upvotes: 3

Views: 259

Answers (1)

JeJo
JeJo

Reputation: 33092

Why is this not working and how should I fix it?

In order to work if constexpr (i.e. discard the false statement at compile time), you need to make it template depended.

From cppreference.com, under the if constexpr section:

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive:

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // Error even though in discarded statement
    }
}

Therefore, the fix is to wrap the statement into a template function, as follows:

template<typename T1, typename T2> auto func()
{
    if constexpr (HasFriction<T1, T2>::value) {
        MyStruct<A, C> f;
        return f.value;
    }
    else {
        MyStruct<A, C> no_f;
        return 0;
    }
}

Now in main()

func<A, B>();

See a demo

Upvotes: 5

Related Questions