#include <iostream>

struct a {
  enum LOCAL_A { A1, A2 };
};
enum class b { B1, B2 };

int foo(int input) { return input; }

int main(void) {
  std::cout << foo(a::A1) << std::endl;
  std::cout << foo(static_cast<int>(b::B2)) << std::endl;
}

a::LOCAL_A是强类型enum试图实现的目标,但有一个小小的区别:普通enum可以转换为整数类型,而强类型enum如果没有强制转换就不能做到这一点。

那么,有没有一种方法可以将强类型枚举值转换为整数类型而不进行强制转换呢?如果是,怎么做?


当前回答

没有隐式转换(通过设计)的原因在其他答案中给出了。

我个人使用一元操作符+从枚举类转换到它们的底层类型:

template <typename T>
constexpr auto operator+(T e) noexcept
    -> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>>
{
    return static_cast<std::underlying_type_t<T>>(e);
}

这给了相当小的“输入开销”:

std::cout << foo(+b::B2) << std::endl;

我实际上使用宏创建枚举和操作符函数在一个镜头。

#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }

其他回答

不。没有自然的方法。

事实上,在c++ 11中使用强类型枚举类的动机之一是防止它们无声地转换为int。

强类型枚举旨在解决多个问题,而不仅仅是你在问题中提到的范围问题:

提供类型安全,从而消除通过积分提升到整数的隐式转换。 指定基础类型。 提供强作用域。

因此,不可能隐式地将强类型枚举转换为整数,甚至是它的底层类型——这就是其思想。因此必须使用static_cast来显式地进行转换。

如果你唯一的问题是作用域,并且你真的想要隐式提升为整数,那么你最好使用非强类型enum和它声明的结构的作用域。

简单的回答是你不能像上面的帖子指出的那样。但对于我的情况,我只是不想让名称空间混乱,但仍然有隐式转换,所以我只是这样做:

#include <iostream>

using namespace std;

namespace Foo {
   enum Foo { bar, baz };
}

int main() {
   cout << Foo::bar << endl; // 0
   cout << Foo::baz << endl; // 1
   return 0;
}

命名空间增加了一层类型安全,而我不必静态地将任何枚举值强制转换为底层类型。

An extension to the answers from R. Martinho Fernandes and Class Skeleton: Their answers show how to use typename std::underlying_type<EnumType>::type or std::underlying_type_t<EnumType> to convert your enumeration value with a static_cast to a value of the underlying type. Compared to a static_cast to some specific integer type, like, static_cast<int> this has the benefit of being maintenance friendly, because when the underlying type changes, the code using std::underlying_type_t will automatically use the new type.

然而,这有时不是你想要的:假设你想直接打印出枚举值,例如std::cout,如下例所示:

enum class EnumType : int { Green, Blue, Yellow };
std::cout << static_cast<std::underlying_type_t<EnumType>>(EnumType::Green);

如果你稍后将底层类型更改为字符类型,例如uint8_t,那么EnumType::Green的值将不会作为数字打印,而是作为字符打印,这很可能不是你想要的。因此,您有时更愿意将枚举值转换为类似于“底层类型,但在必要时使用整数提升”的类型。

如果需要,可以对强制转换的结果应用一元运算符+来强制提升整数。然而,你也可以使用std::common_type_t(同样来自头文件<type_traits>)来做以下事情:

enum class EnumType : int { Green, Blue, Yellow };
std::cout << static_cast<std::common_type_t<int, std::underlying_type_t<EnumType>>>(EnumType::Green);

最好将这个表达式包装在某个helper模板函数中:

template <class E>
constexpr std::common_type_t<int, std::underlying_type_t<E>>
enumToInteger(E e) {
    return static_cast<std::common_type_t<int, std::underlying_type_t<E>>>(e);
}

这样看起来更友好,对底层类型的更改维护更友好,并且不需要使用operator+的技巧:

std::cout << enumToInteger(EnumType::Green);

没有隐式转换(通过设计)的原因在其他答案中给出了。

我个人使用一元操作符+从枚举类转换到它们的底层类型:

template <typename T>
constexpr auto operator+(T e) noexcept
    -> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>>
{
    return static_cast<std::underlying_type_t<T>>(e);
}

这给了相当小的“输入开销”:

std::cout << foo(+b::B2) << std::endl;

我实际上使用宏创建枚举和操作符函数在一个镜头。

#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }