I'm getting the error:
Error C2154 '_Ty': only enumeration type is allowed as an argument to compiler intrinsic type trait '__underlying_type'
I thought it shouldn't be resolving underlying_type to underlying_type, because I first check whether T is an enum. Here is the code:
template <typename T>
struct Foo
{
static inline constexpr bool isArgIntegral = std::is_integral<T>::value;
static inline constexpr bool isArgEnum = std::is_enum_v<T>;
using integral_underlying_type = std::conditional<isArgEnum, std::underlying_type_t<T>, T>;
};
int main()
Foo<int> g; // only enumeration type is allowed as an argument to compiler intrinsic type trait '__underlying_type'
}
So is it the case that in a call to std::conditional, instead of first checking the condition (1st argument), it creates the classes of the 2nd and 3rd arguments regardless of the condition, and hence why I'm getting the error that I can't call underlying_type with an 'int'?
How do I go about getting the integral type of the T template argument, whether it's an integral or an enum?
Edit: My next attempt is to place the typedef in an if constexpr:
if constexpr (std::is_enum_v<T>)
{
using integral_underlying_type = std::underlying_type_t<T>;
// Now std::underlying_type_t won't be called at all unless T is enum, right?
}
Unfortunately, std::integral_underlying_type
is not SFINAE friendly until C++20.
You can then delay instantiation of std::underlying_type<T>::type
:
template <typename T>
struct Foo
{
using integral_underlying_type =
typename std::conditional_t<std::is_enum_v<T>,
std::underlying_type<T>,
type_identity<T>>::type;
};
Notice the double ::type
in std::conditional<cond, T1, T2>::type::type
(hidden with _t
). The extra ::type
is done outside the conditional instead of inside (and so the need of type_identity
).