Home > Net >  Determine if a generic type is a primitive or enum with underlying primitive at compile time C in
Determine if a generic type is a primitive or enum with underlying primitive at compile time C in

Time:09-15

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.

  • Related