Kyle
Kyle

Reputation: 454

How to know underlying type of class enum?

I have a variable declared as:

enum class FooEnum: uint64_t {}

and I would like to cast to its base-type, but I don't want to hardcode the base-type. For instance, something like this:

FooEnum myEnum;
uint64_t * intPointer = (underlying_typeof(myEnum))&myEnum;

Is this possible?

Upvotes: 38

Views: 14288

Answers (4)

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361442

Since C++ 11 you can use this:

The doc says,

Defines a member typedef type of type that is the underlying type for the enumeration T.

So you should be able to do this:

#include <type_traits> //include this

FooEnum myEnum;
auto pointer = static_cast<std::underlying_type<FooEnum>::type*>(&myEnum);

In C++ 14 it has been a bit simplified (note there is no ::type):

auto pointer = static_cast<std::underlying_type_t<FooEnum>*>(&myEnum);

And finally since C++ 23 one can get value without explicit cast (docs):

auto value = std::to_underlying<FooEnum>(myEnum);

Upvotes: 46

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

Both Visual C++ 10.0 and MinGW g++ 4.6.1 lack std::underlying_type, but both accept this code:

template< class TpEnum >
struct UnderlyingType
{
    typedef typename conditional<
        TpEnum( -1 ) < TpEnum( 0 ),
        typename make_signed< TpEnum >::type,
        typename make_unsigned< TpEnum >::type
        >::type T;
};

Upvotes: 9

Zoner
Zoner

Reputation: 626

Here is another approach for when underlying_type is not present. This method doesn't attempt to detect the signed-ness of the enum, just give you a type of the same size, which is more than enough for a lot of situations.

template<int>
class TIntegerForSize
{
    typedef void type;
};

template<>
struct TIntegerForSize<1>
{
    typedef uint8_t type;
};

template<>
struct TIntegerForSize<2>
{
    typedef uint16_t type;
};

template<>
struct TIntegerForSize<4>
{
    typedef uint32_t type;
};

template<>
struct TIntegerForSize<8>
{
    typedef uint64_t type;
};

template<typename T>
struct TIntegerForEnum
{
    typedef typename TIntegerForSize<sizeof(T)>::type type;
};

Usage:

enum EFoo {Alpha, Beta};
EFoo f = Alpha;
TIntegerForEnum<EFoo>::type i = f;
TIntegerForEnum<decltype(f)>::type j = f;

Upvotes: 2

Howard Hinnant
Howard Hinnant

Reputation: 218770

Your guessed syntax is amazingly close. You're looking for std::underlying_type in <type_traits>:

#include <type_traits>
#include <cstdint>

enum class FooEnum: std::uint64_t {};

int main()
{
    FooEnum myEnum;
    uint64_t* intPointer = (std::underlying_type<FooEnum>::type*)&myEnum;
}

Upvotes: 20

Related Questions