Can an enum class be converted to the underlying type?

后端 未结 4 1305
不思量自难忘°
不思量自难忘° 2020-11-28 01:57

Is there a way to convert an enum class field to the underlying type? I thought this would be automatic, but apparently not.

enum class my_field         


        
相关标签:
4条回答
  • 2020-11-28 02:35

    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.

    0 讨论(0)
  • 2020-11-28 02:37

    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
    
    0 讨论(0)
  • 2020-11-28 02:42

    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!
    
    0 讨论(0)
  • 2020-11-28 02:44

    I find the following function underlying_cast useful when having to serialise enum values correctly.

    namespace util
    {
    
    namespace detail
    {
        template <typename E>
        using UnderlyingType = typename std::underlying_type<E>::type;
    
        template <typename E>
        using EnumTypesOnly = typename std::enable_if<std::is_enum<E>::value, E>::type;
    
    }   // namespace util.detail
    
    
    template <typename E, typename = detail::EnumTypesOnly<E>>
    constexpr detail::UnderlyingType<E> underlying_cast(E e) {
        return static_cast<detail::UnderlyingType<E>>(e);
    }
    
    }   // namespace util
    
    enum SomeEnum : uint16_t { A, B };
    
    void write(SomeEnum /*e*/) {
        std::cout << "SomeEnum!\n";
    }
    
    void write(uint16_t /*v*/) {
        std::cout << "uint16_t!\n";
    }
    
    int main(int argc, char* argv[]) {
        SomeEnum e = B;
        write(util::underlying_cast(e));
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题