枚举类可以转换为基础类型吗?


112

有没有一种方法可以将enum class字段转换为基础类型?我认为这将是自动的,但显然不是。

enum class my_fields : unsigned { field = 1 };

unsigned a = my_fields::field;

该作业已被GCC拒绝。error: cannot convert 'my_fields' to 'unsigned int' in assignment


4
如果要转换为基础类型,请使用enum
2013年

1
仅供参考,该规则在中定义[C++11: 7.2/9]
Lightness Races in Orbit

5
@Pubby可悲的是,没有范围的“枚举”会污染所有枚举数的外部范围。las,这两个世界都没有最好的选择(无论如何从C ++ 14开始),它干净地嵌套了作用域,同时隐式转换为基本类型(当您通过传递更多派生类型时,这与C ++处理其他类继承的方式不一致。值或对具有基本类型的函数的引用)。
Dwayne Robinson

2
@DwayneRobinson是的。将无作用域的枚举粘贴在结构或(最好是)名称空间中。因此,它是作用域的,并且仍然具有隐式int转换。(尽管我一定会三思而后行,为什么需要转换为int并可能考虑是否有更好的方法。)
Pharap

Answers:


177

我认为您可以使用std :: underlying_type知道底层类型,然后使用cast:

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

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

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

这样,您不必假设基础类型,也不必在enum classlike之类的定义中提及它enum class my_fields : int { .... }

您甚至可以编写一个通用转换函数,该函数应该能够将任何 转换enum class为其基础整数类型:

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

然后使用它:

auto value = to_integral(my_fields::field);

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

并且由于该函数声明为constexpr,因此可以在需要常量表达式的地方使用它:

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

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

现在我们处于未来:template <typename T> auto to_integral(T e) { return static_cast<std::underlying_type_t<T>>(e); }
Ryan Haining

1
@RyanHaining:谢谢。(顺便说一句,您constexpr将来也将拥有;实际上比我在2013年拥有的强大得多:P)
Nawaz

41

您不能对其进行隐式转换,但是可以进行显式转换:

enum class my_fields : unsigned { field = 1 };

// ...

unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK

同样要注意的事实是,分号应该位于枚举定义中的闭合花括号之后,而不是之前。


0

underlying_cast当必须正确地枚举枚举值时,我发现以下函数很有用。

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

正如其他人指出的那样,没有隐式强制类型转换,但是您可以使用显式static_cast。我在代码中使用以下辅助函数来与枚举类型及其基础类进行相互转换。

    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 /programming/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);
    }

使用代码

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.