I'm trying to determine at compile time within a template function if the type T is either a primitive type or an enum with underlying primitive type.
In code, I'm trying to do this
template <typename T>
bool foo(T& input)
{
bool isPrimitive = std::is_fundamental<T>::value || (std::is_enum<T>::value && std::is_fundamental<std::underlying_type<T>::type>::value);
// We want to do things using isPrimitive, but not important so omitted.
return isPrimitive; //return this value just to avoid warnings.
}
This fails to compile when foo is invoked with T not being an enum, since std::underlying_type<T>::type
doesn't exist in that case.
enum class Bar : int
{
DUMMYCASE,
};
int main()
{
int test1;
Bar test2;
foo(test1); // fails
foo(test2); // ok
}
I've looked at std::conditional and std::enable_if, as well as this answer SFINAE not happening with std::underlying_type but cannot see how this can be done. It seems like enable_if only works in template params.
How can I rewrite the line such that it compiles when T is not an enum? Ideally I would like to avoid changing the function signature.
bool isPrimitive = std::is_fundamental<T>::value || (std::is_enum<T>::value && std::is_fundamental<std::underlying_type<T>::type>::value);
CodePudding user response:
Beside the fact that enums support only integral types you could write:
template <typename T>
bool foo(T& input)
{
constexpr bool isPrimitive = [](){
if constexpr (std::is_fundamental_v<T>){
return true;
}
if constexpr (std::is_enum_v<T>){
using underlying_type = typename std::underlying_type<T>::type;
if constexpr (std::is_fundamental_v<underlying_type>){
return true;
}
}
return false;
}();
// We want to do things using isPrimitive, but not important so omitted.
return isPrimitive; //return this value just to avoid warnings.
}
The problem with your code is, that std::underlying_type is instantiated for non-enums, too. In addition there is a missing typename disambiguator.
std::underlying_type<T>::type
is a dependent name and must be prefixed with "typename" - otherwise the compiler asumes a non-type.