#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 E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
    return static_cast<typename std::underlying_type<E>::type>(e);
}

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

其他回答

不。没有自然的方法。

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

由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;

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

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

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

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

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

因此,不可能隐式地将强类型枚举转换为整数,甚至是它的底层类型——这就是其思想。因此必须使用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;
    }
}