Can an enum class be converted to the underlying type?
You cannot convert it implicitly, but an explicit cast is possible:
enum class my_fields : unsigned { field = 1 };
// ...
unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK
Also mind the fact, that the semicolon should be after the closed curly brace in your enum's definition, not before.
With C++23 you'll finally get a library function for this:
std::to_underlying
It is already implemented in the standard libraries of GCC 11, Clang 13, and MSVC 19.30 (aka 2022 17.0).
Until you're able to use C++23 I recommend you (re)name any custom implementation to to_underlying
and place it between a #if !defined(__cpp_lib_to_underlying)
#endif
block, which is the associated feature test macro. This way you can simply ditch the code at some point in the future when C++23 becomes available for you.
As others have pointed out there is no implicit cast, but you can use an explicit static_cast
. I use the following helper functions in my code to convert to and from an enum type and its underlying class.
template<typename EnumType>
constexpr inline decltype(auto) getIntegralEnumValue(EnumType enumValue)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
using EnumValueType = std::underlying_type_t<EnumType>;
return static_cast<EnumValueType>(enumValue);
}
template<typename EnumType,typename IntegralType>
constexpr inline EnumType toEnum(IntegralType value)
{
static_assert(std::is_enum<EnumType>::value,"Enum type required");
static_assert(std::is_integral<IntegralType>::value, "Integer required");
return static_cast<EnumType>(value);
}
template<typename EnumType,typename UnaryFunction>
constexpr inline void setIntegralEnumValue(EnumType& enumValue, UnaryFunction integralWritingFunction)
{
// Since using reinterpret_cast on reference to underlying enum type is UB must declare underlying type value and write to it and then cast it to enum type
// See discussion on https://stackoverflow.com/questions/19476818/is-it-safe-to-reinterpret-cast-an-enum-class-variable-to-a-reference-of-the-unde
static_assert(std::is_enum<EnumType>::value,"Enum type required");
auto enumIntegralValue = getIntegralEnumValue(enumValue);
integralWritingFunction(enumIntegralValue);
enumValue = toEnum<EnumType>(enumIntegralValue);
}
Usage code
enum class MyEnum {
first = 1,
second
};
MyEnum myEnum = MyEnum::first;
std::cout << getIntegralEnumValue(myEnum); // prints 1
MyEnum convertedEnum = toEnum(1);
setIntegralEnumValue(convertedEnum,[](auto& integralValue) { ++integralValue; });
std::cout << getIntegralEnumValue(convertedEnum); // prints 2
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!