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>{}
).