C++ 为什么int类型的枚举类值不能用作int

C++ 为什么int类型的枚举类值不能用作int,c++,enum-class,C++,Enum Class,我想将一个旧式的enum更改为enum class:int,因为它有自己的作用域 但是编译器抱怨在整数算术中使用这些值。 但是为什么呢?因为枚举是显式类型化为int的 例如: enum class MsgType : int { Output = 1, Input = 2, Debug = 3 }; enum class MsgSender : int { A = 1, B = 2, C = 3 }; // later

我想将一个旧式的enum更改为enum class:int,因为它有自己的作用域

但是编译器抱怨在整数算术中使用这些值。 但是为什么呢?因为枚举是显式类型化为int的

例如:

  enum class MsgType : int {
    Output = 1,
    Input  = 2,
    Debug  = 3
  };
  enum class MsgSender : int {
    A = 1,
    B = 2,
    C = 3
  };


  // later in code
  int id = (MsgType::Input << 16) + (MsgSender::A);
产生


错误C2678:二进制',这是功能。作用域枚举不能隐式转换为整数,因此不能使用它们代替整数。它们是强类型的设计。如果需要隐式转换,请使用非范围枚举

enum MsgType : int {
  Output = 1,
  Input  = 2,
  Debug  = 3
};
enum MsgSender : int {
  A = 1,
  B = 2,
  C = 3
};
基础类型的作用域和规范是正交的

或者,如果只希望定义某些操作,而枚举通常保持强类型,则可以重载相应的运算符来完成此操作

int operator<<(MsgType, int); // etc
但是如果我不希望它们是可转换的,为什么我要将类型指定为int


确保一定的布局。遵循特定的ABI。允许向前声明类型。

类型安全性是使用新的作用域枚举的主要原因可能名称有点误导。如果您只需要一个作用域为且可以隐式转换为整数的枚举,则可以将其包装在结构或命名空间中:

struct MsgSender {
   enum Values {
      A = 1,
      B = 2,
      C = 3
   };
};
缺点是类型现在是MsgSender::Values,但值是MsgSender::A等


对于作用域枚举,必须对进行静态转换才能获得整数。

可以通过静态转换显式转换它们

  int id = (static_cast<uint32_t>(MsgType::Input) << 16) + (static_cast<uint32_t>(MsgSender::A)) ;

不能将c++11作用域枚举直接用作int,但可以将其转换为int

主要是由于类型安全原因,非作用域枚举可以在枚举内泄漏名称,而作用域枚举没有泄漏名称的风险,名称只能在枚举内可见

<> C++中有2种枚举形式,

C++98样式非范围枚举: 枚举颜色{红、绿、黄};, 可以隐式转换为int

C++11作用域枚举:枚举类{Red,Green,Yellow};, 不能隐式转换为int,只能使用强制转换转换为其他类型,如static\u castmy\u color

与非作用域枚举相比,作用域枚举有3个优点:

减少污染; 强型安全; 作用域枚举可以向前声明,非作用域枚举需要额外的工作才能向前声明; 同时,非作用域枚举比作用域枚举更灵活

作用域枚举和非作用域枚举都支持基础类型的规范,作用域枚举的默认基础类型为int。非作用域枚举没有默认基础类型,它依赖于编译器,根据值的范围,可以是char或int

枚举类颜色:std::uint8{Red,Green,Yellow};//定义

枚举颜色:std::uint8{Red,Green,Yellow};//远期申报

只有在声明指定了基础类型时,才能向前声明非作用域枚举

实际上,更喜欢作用域枚举而不是非作用域枚举


<>参见Scott Meyers的《现代C++》,第10项:比较范围内的枚举到非作用域枚举。

在移位之前,你试过抛出吗?枚举上可能没有移位运算符。因为它仍然是一个类,而不是一个int。这就是枚举类的要点,它是一个专用类型,不仅仅是整数的别名。但是,如果您切换到类型安全的枚举并期望它不是类型安全的,这似乎是不合逻辑的。这就是新的和旧的主要区别enums@UnholySheep我想将枚举值与对象进行更多的比较,因为它与对象一样使用。在这个例子中,一个从intYes派生的类的对象,语法是类似的。但不,这并不意味着相同。很不幸,但没什么新奇的。嗨,对不起我的错误,我的第四项不正确。我修改了它。