Home > Enterprise >  if constexpr std::is_same under VS 2022
if constexpr std::is_same under VS 2022

Time:03-16

I have converted one of my projects from VS 2019 to VS 2022 and the following conditional compilation template doesn't compile properly anymore:

struct T_USER;
struct T_SERVICE;

template<typename T>
class system_state
{
 public:
    system_state();
};


template<typename T>
system_state<T>::system_state()
{
    if constexpr (std::is_same<T, T_USER>)
    {
        std::cout << "User templ\n";
    }
    else if constexpr (std::is_same<T, T_SERVICE>)
    {
        std::cout << "Service templ\n";
    }
    else
    {
        //Bad type
        static_assert(false, "Bad template type in T: must be either T_USER or T_SERVICE");

        std::cout << "Unknown templ\n";
    }
}

The idea was to compile parts of code in system_state depending on a specific template, as such:

int main()
{
    system_state<T_USER> user_state;
}

But now the if constexpr std::is_same doesn't seem to detect my T and I'm always getting my static_assert clause:

Bad template type in T: must be either T_USER or T_SERVICE

What has changed? It used to work in VS 2019.

CodePudding user response:

The code is ill-formed because for constexpr if:

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

template <typename T>
void f() {
     if constexpr (std::is_arithmetic_v<T>)
         // ...
     else
       static_assert(false, "Must be arithmetic"); // ill-formed: invalid for every T
}

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

template<class> inline constexpr bool dependent_false_v = false;
template <typename T>
void f() {
     if constexpr (std::is_arithmetic_v<T>)
         // ...
     else
       static_assert(dependent_false_v<T>, "Must be arithmetic"); // ok
}

You can use the type-dependent expression above in the else branch too, e.g.

//Bad type
static_assert(dependent_false_v<T>, "Bad template type in T: must be either T_USER or T_SERVICE");

BTW: In if constexpr (std::is_same<T, T_USER>), std::is_same<T, T_USER> is type but not a bool value; you should change it to std::is_same_v<T, T_USER>, or std::is_same<T, T_USER>::value, or std::is_same<T, T_USER>() (std::is_same<T, T_USER>{}).

  • Related