【问题标题】:why can enum class values of type int not be used as int为什么 int 类型的枚举类值不能用作 int
【发布时间】:2020-06-30 08:54:44
【问题描述】:

我想将旧样式的 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:二进制“

这对我来说似乎有些不合逻辑。

编辑:
我完全意识到投掷它们的可能性。但是如果我不希望它们是可转换的,我为什么要将类型指定为int。特别是如果语法暗示某种“继承自int

【问题讨论】:

  • 您在换档前尝试过投射吗?枚举上可能没有移位运算符。
  • 因为它仍然是class,而不是int。这就是enum class 的意义所在,它是一种专用类型,而不仅仅是整数的别名
  • 抱歉,但您切换到类型安全的枚举并期望它不是类型安全的似乎不合情理。这就是新旧枚举之间的主要区别
  • @UnholySheep 我想将枚举值更多地与对象进行比较,因为它像一个对象一样使用。在这种情况下,是一个派生自int 的类的对象
  • 是的,语法类似。但不,这并不意味着相同。不幸的是,但没什么特别的。

标签: c++ enum-class


【解决方案1】:

这就是特色。作用域枚举不能隐式转换为整数,因此不能使用它们代替整数。它们在设计上是强类型的。如果您想要隐式转换,请使用无范围枚举。

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。允许前向声明类型。

【讨论】:

    【解决方案2】:

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

    struct MsgSender {
       enum Values {
          A = 1,
          B = 2,
          C = 3
       };
    };
    

    缺点是类型现在是MsgSender::Values,但值是MsgSender::A 等等。

    对于作用域枚举,您必须将static_cast 转换为std::underlying_type&lt;MsgSener&gt; 才能获取整数。

    【讨论】:

      【解决方案3】:

      您可以通过 static_cast 显式转换它们。

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

      【讨论】:

        【解决方案4】:

        您不能将 c++11 范围内的枚举直接用作 int,但可以将其转换为 int

        主要是因为类型安全的原因,无作用域的枚举可以在枚举内部泄漏名字,而作用域的枚举没有泄漏名字的风险,名字只能在内部可见。

        目前c++中有2种枚举。

        C++98 风格的无范围枚举: enum Color {Red, Green, Yellow};, 可以隐式转换为int。

        C++11 范围枚举:enum class{Red, Green, Yellow};, 不能隐式转换为int,只能使用强制转换转换为其他类型,如static_cast&lt;int&gt;(my_color)

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

        1. 减少命名空间污染;
        2. 强类型安全性;
        3. 作用域枚举可以前向声明,无作用域枚举需要额外的工作才能前向声明;

        同时,无作用域枚举比作用域枚举更灵活。

        作用域枚举和非作用域枚举都支持底层类型的规范,作用域枚举的默认底层类型是int。无作用域的枚举没有默认的底层类型,这取决于编译器,可以是charint,具体取决于值的范围。

        enum class Color: std::uint8_t{Red, Green, Yellow}; // Definition

        enum Color: std::uint8_t{Red, Green, Yellow}; // Forward Declaration

        只有在声明指定了基础类型时,才可以前向声明无作用域的枚举。

        在实践中,更喜欢有范围的枚举而不是无范围的枚举。

        参见 Scott Meyers 所著的“Effective Modern C++”一书,第 10 项:preferred scoped enums to unscoped enums。

        【讨论】:

        • 嗨,很抱歉我的错误,我的第 4 项不正确。我修改了它。
        猜你喜欢
        • 1970-01-01
        • 2015-02-22
        • 1970-01-01
        • 2023-01-23
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 2016-01-18
        • 2012-12-30
        相关资源
        最近更新 更多