if constexpr std::is_same 在 VS 2022 下

if constexpr std::is_same under VS 2022

我已将我的一个项目从 VS 2019 转换为 VS 2022,但以下条件编译模板无法再正确编译:

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";
    }
}

我们的想法是根据特定模板编译 system_state 中的部分代码,例如:

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

但现在 if constexpr std::is_same 似乎没有检测到我的 T,我总是得到我的 static_assert 子句:

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

发生了什么变化?它曾经在 VS 2019 中工作。

代码是 ill-formed 因为 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
}

您也可以在 else 分支中使用上面的 type-dependent 表达式 ,例如

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

顺便说一句:在 if constexpr (std::is_same<T, T_USER>) 中,std::is_same<T, T_USER> 是类型而不是 bool 值;您应该将其更改为 std::is_same_v<T, T_USER>,或 std::is_same<T, T_USER>::value,或 std::is_same<T, T_USER>()std::is_same<T, T_USER>{})。