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 anint
orunsigned 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
C++ Copy Constructor Gets Called Instead of Initializer_List<>
The Cxx Compiler Identification Is Unknown
How to Control My Pc's Fan Speed Using C++ in Vista
Memoized, Recursive Factorial Function
Drawing in a Win32 Console on C++
Why Is Std::Cout So Time Consuming
Are Dollar-Signs Allowed in Identifiers in C++03
Why Array Index Start from '0'
How Does Sizeof Know the Size of the Operand Array
Why Are Designated Initializers Not Implemented in G++
Why Can't I Use <Experimental/Filesystem> with G++ 4.9.2
Should I Include Stddef.H or Cstddef for Size_T