How to Know Underlying Type of Class Enum

Can an enum class be converted to the underlying type?

I think you can use std::underlying_type to know the underlying type, and then use cast:

#include <type_traits> //for std::underlying_type

typedef std::underlying_type<my_fields>::type utype;

utype a = static_cast<utype>(my_fields::field);

With this, you don't have to assume the underlying type, or you don't have to mention it in the definition of the enum class like enum class my_fields : int { .... } or so.

You can even write a generic convert function that should be able to convert any enum class to its underlying integral type:

template<typename E>
constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}

then use it:

auto value = to_integral(my_fields::field);

auto redValue = to_integral(Color::Red);//where Color is an enum class!

And since the function is declared to be constexpr, you can use it where constant expression is required:

int a[to_integral(my_fields::field)]; //declaring an array

std::array<int, to_integral(my_fields::field)> b; //better!

How to know underlying type of class enum?

Since C++ 11 you can use this:

  • std::underlying_type class template to know the underlying type of enum.

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);

What is the underlying type of a c++ enum?

From N4659 C++ 7.2/5:

For an enumeration whose underlying type is not fixed, the underlying type is an integral type that can represent all the enumerator values defined in the enumeration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-defined which integral type is used as the underlying type except that the underlying type shall not be larger than int unless the value of an enumerator cannot fit in an int or unsigned int. If the enumerator-list is empty, the underlying type is as if the enumeration had a single enumerator with value 0.

Underlying type of a C++ enum in C++0x

I haven't read any C++0x stuff so I couldn't comment on that.

As for serializing, you don't need the switch when reading the enum back in - just cast it to the enum type.

However, I don't cast when writing to the stream. This is because I often like to write an operator<< for the enum so I can catch bad values being written, or I can then decide to write out a string instead.

enum color { red, green, blue };
color c = red;

// to serialize
archive << c; // Removed cast

// to deserialize
int i;
archive >> i;
c = (color)i; // Removed switch

How should I check whether an underlying-type value is an enumerated value?

There is currently no way to do this.

There are reflection proposals that may make it into c++20 and/or c++23 that let you iterate (at compile, and hence run, time) over the enumerated values in an enum. Using that the check would be relatively easy.

Sometimes people do manual enum reflection, often using macros.

enum underlying type vs normal type

C++11 introduced restrictions on "narrowing conversions" and where they are and aren't allowed. Tucked away in 5.19§3 is a clause that describes "converted constant expression"s and specifically precludes narrowing conversions, and then notes that such expressions may be used in [...] enumerator initializers. Thus, you can't do:

enum class Foo : char { one = 128 };
unsigned char uc1 = {-1};

but you can do

enum class Foo : char { one = (char)128 };
unsigned char uc1 = -1;

5.19 [expr.const] §3

[...] A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-torvalue conversions (4.1), integral promotions (4.5), and integral conversions (4.7) other than narrowing conversions (8.5.4). [ Note: such expressions may be used in new expressions (5.3.4), as case expressions (6.4.2), as enumerator initializers if the underlying type is fixed (7.2), as array bounds (8.3.4), and as integral or enumeration non-type template arguments (14.3). —end note ]

static_cast to enum class from underlying type value and switch for compiler assistance

It is legal C++.

The drawback is the DRY violation, but avoiding it is difficult.

In c++23 we'll have reflection and be able to generate equivalent code (without having to rely on compiler warnings to make sure we didn't miss any). Reflection syntax is still a bit in flux, but every version I have read over was able to handle that problem.



Related Topics



Leave a reply



Submit