How to assert that a constexpr if else clause never happen?

You have to make the discarded statement dependent of the template parameters

template <class...> constexpr std::false_type always_false{};

if constexpr(condition1){
    ...
} else if constexpr (condition2) {
   ....
} else if constexpr (condition3) {
  ....
} else {       
    static_assert(always_false<T>);
}

This is so because

[temp.res]/8 - The program is ill-formed, no diagnostic required, if

no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or ...


Here's a workaround from cppreference.com, i.e. use a type-dependent expression instead.

Note: the discarded statement can't be ill-formed for every possible specialization:

The common workaround for such a catch-all statement is a type-dependent expression that is always false:

e.g.

template<class T> struct dependent_false : std::false_type {};

then

static_assert(dependent_false<T>::value);

taking a slightly different tack...

#include <ciso646>

template<auto x> void something();

template<class...Conditions>
constexpr int which(Conditions... cond)
{
    int sel = 0;
    bool found = false;
    auto elect = [&found, &sel](auto cond)
    {
        if (not found)
        {
            if (cond)
            {
                found = true;
            }
            else
            {
                ++sel;
            }
        }
    };

    (elect(cond), ...);
    if (not found) throw "you have a logic error";
    return sel;
}

template<bool condition1, bool condition2, bool condition3>
void foo()
{
    auto constexpr sel = which(condition1, condition2, condition3);
    switch(sel)
    {
        case 0:
            something<1>();
            break;
        case 1:
            something<2>();
            break;
        case 2:
            something<3>();
            break;
    }
}

int main()
{
    foo<false, true, false>();
//    foo<false, false, false>(); // fails to compile
}

As I understand it, which is evaluated in constexpr context, which means that it is legal unless the program has to follow a code path that is illegal in a constexpr context.

For all expected cases, the throw path is not taken, so the function is legal. When illegal inputs are provided, we go down the ill-formed path, which causes a compiler error.

I'd be interested to know whether this solution is strictly correct from a language-lawyer perspective.

It works on gcc, clang and MSVC.

...or for fans of obfuscated code...

template<class...Conditions>
constexpr int which(Conditions... cond)
{
    auto sel = 0;
    ((cond or (++sel, false)) or ...) or (throw "program is ill-formed", false);
    return sel;
}