"constexpr if" vs "if" with optimizations - why is "constexpr" needed?

Solution 1:

This is easy to explain through an example. Consider

struct Cat { void meow() { } };
struct Dog { void bark() { } };

and

template <typename T>
void pet(T x)
{
    if(std::is_same<T, Cat>{}){ x.meow(); }
    else if(std::is_same<T, Dog>{}){ x.bark(); }
}

Invoking

pet(Cat{});
pet(Dog{});

will trigger a compilation error (wandbox example), because both branches of the if statement have to be well-formed.

prog.cc:10:40: error: no member named 'bark' in 'Cat'
    else if(std::is_same<T, Dog>{}){ x.bark(); }
                                     ~ ^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here
    pet(Cat{});
    ^
prog.cc:9:35: error: no member named 'meow' in 'Dog'
    if(std::is_same<T, Cat>{}){ x.meow(); }
                                ~ ^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here
    pet(Dog{});
    ^

Changing pet to use if constexpr

template <typename T>
void pet(T x)
{
    if constexpr(std::is_same<T, Cat>{}){ x.meow(); }
    else if constexpr(std::is_same<T, Dog>{}){ x.bark(); }
}

only requires the branches to be parseable - only the branch that matches the condition needs to be well-formed (wandbox example).

The snippet

pet(Cat{});
pet(Dog{});

will compile and work as expected.