#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如果没有强制转换就不能做到这一点。

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


当前回答

不。没有自然的方法。

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

其他回答

不。没有自然的方法。

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

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

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

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

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

正如许多人所说,没有办法在不增加开销和太多复杂性的情况下自动转换,但是如果在某个场景中要多使用一些强制转换,则可以通过使用lambdas来减少输入并使其看起来更好。这将增加一些函数调用开销,但与下面看到的长static_cast字符串相比,将使代码更具可读性。这可能不适用于项目范围,但只适用于类范围。

#include <bitset>
#include <vector>

enum class Flags { ......, Total };
std::bitset<static_cast<unsigned int>(Total)> MaskVar;
std::vector<Flags> NewFlags;

-----------
auto scui = [](Flags a){return static_cast<unsigned int>(a); };

for (auto const& it : NewFlags)
{
    switch (it)
    {
    case Flags::Horizontal:
        MaskVar.set(scui(Flags::Horizontal));
        MaskVar.reset(scui(Flags::Vertical)); break;
    case Flags::Vertical:
        MaskVar.set(scui(Flags::Vertical));
        MaskVar.reset(scui(Flags::Horizontal)); break;

   case Flags::LongText:
        MaskVar.set(scui(Flags::LongText));
        MaskVar.reset(scui(Flags::ShorTText)); break;
    case Flags::ShorTText:
        MaskVar.set(scui(Flags::ShorTText));
        MaskVar.reset(scui(Flags::LongText)); break;

    case Flags::ShowHeading:
        MaskVar.set(scui(Flags::ShowHeading));
        MaskVar.reset(scui(Flags::NoShowHeading)); break;
    case Flags::NoShowHeading:
        MaskVar.set(scui(Flags::NoShowHeading));
        MaskVar.reset(scui(Flags::ShowHeading)); break;

    default:
        break;
    }
}

由R. Martinho Fernandes提供的答案的c++ 14版本将是:

#include <type_traits>

template <typename E>
constexpr auto to_underlying(E e) noexcept
{
    return static_cast<std::underlying_type_t<E>>(e);
}

与前面的答案一样,这将适用于任何类型的枚举和底层类型。我添加了noexcept关键字,因为它永远不会抛出异常。


更新 这也出现在Scott Meyers的《Effective Modern c++》中。见第10项(在我这本书的最后几页有详细说明)。


c++ 23版本将使用std:: to_底层函数:

#include <utility>

std::cout << std::to_underlying(b::B2) << std::endl;

...或者如果底层类型可以是1字节类型:

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

对于本地枚举类,这似乎是不可能的,但也许你可以用类来模拟枚举类:

在这种情况下,

enum class b
{
    B1,
    B2
};

相当于:

class b {
 private:
  int underlying;
 public:
  static constexpr int B1 = 0;
  static constexpr int B2 = 1;
  b(int v) : underlying(v) {}
  operator int() {
      return underlying;
  }
};

这在很大程度上相当于最初的enum类。你可以在返回类型为b的函数中直接返回b::B1 for。你可以用它来切换大小写,等等。

根据本例的精神,您可以使用模板(可能与其他东西一起使用)泛化和模拟枚举类语法定义的任何可能的对象。