为什么 enum class int 类型的值不能用作 int
why can enum class values of type int not be used as int
我想将旧式 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);
产生
error C2678: binary '<<': no operator found which takes a left-hand operand of type 'MyClass::MsgType' (or there is no acceptable conversion)
这对我来说似乎有点不合逻辑。
编辑:
我完全知道施放它们的可能性。但是如果我不希望它们是可转换的,为什么我要将类型指定为 int
。特别是如果语法暗示某种“继承自 int
”
这就是功能。作用域枚举不能隐式转换为整数,因此不能使用它们代替整数。它们在设计上是强类型的。如果您想要隐式转换,请使用无范围枚举。
enum MsgType : int {
Output = 1,
Input = 2,
Debug = 3
};
enum MsgSender : int {
A = 1,
B = 2,
C = 3
};
基础类型的作用域和规范是正交的。
或者,如果您只想定义一些操作,而枚举通常保持强类型,您可以重载适当的运算符来实现
int operator<<(MsgType, int); // etc
But if I would not want them to be convertible, why would i specify the type to be int
保证一定的布局。遵循特定的 ABI。允许向前声明类型。
类型安全是使用新作用域枚举的主要原因(也许名称有点误导)。如果你只想要一个有范围的枚举并且可以隐式转换为整数,你可以将它包装在结构或命名空间中:
struct MsgSender {
enum Values {
A = 1,
B = 2,
C = 3
};
};
缺点是类型现在是 MsgSender::Values
,但值是 MsgSender::A
等
对于范围枚举,您必须 static_cast
到 std::underlying_type<MsgSener>
才能获得整数。
您可以通过 static_cast.
显式转换它们
int id = (static_cast<uint32_t>(MsgType::Input) << 16) + (static_cast<uint32_t>(MsgSender::A)) ;
您不能将 c++11 作用域枚举直接用作 int,但可以将其转换为 int
。
主要是因为类型安全的原因,unscoped enum 可以在 enums 内部泄漏名称,而 scoped enum 没有泄漏名称的风险,名称只能在内部可见。
目前c++中有2种枚举。
C++98 风格的无作用域枚举:
enum Color {Red, Green, Yellow};
,
可以隐式转换为 int.
C++11 作用域枚举:enum class{Red, Green, Yellow};
,
不能隐式转换为int,只能使用强制转换为其他类型,如static_cast<int>(my_color)
.
与非作用域枚举相比,作用域枚举有 3 个优势:
- 减少命名空间污染;
- 强类型安全;
- 范围内的枚举可以前向声明,非范围内的枚举需要额外的工作才能前向声明;
同时,无范围枚举比范围枚举更灵活。
作用域枚举和非作用域枚举都支持底层类型的规范,作用域枚举的默认底层类型是int
。 Unscoped enums 没有默认的底层类型,依赖于编译器,可以是 char
或 int
,根据值的范围。
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 项:优先使用作用域枚举而不是非作用域枚举。
我想将旧式 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);
产生
error C2678: binary '<<': no operator found which takes a left-hand operand of type 'MyClass::MsgType' (or there is no acceptable conversion)
这对我来说似乎有点不合逻辑。
编辑:
我完全知道施放它们的可能性。但是如果我不希望它们是可转换的,为什么我要将类型指定为 int
。特别是如果语法暗示某种“继承自 int
”
这就是功能。作用域枚举不能隐式转换为整数,因此不能使用它们代替整数。它们在设计上是强类型的。如果您想要隐式转换,请使用无范围枚举。
enum MsgType : int {
Output = 1,
Input = 2,
Debug = 3
};
enum MsgSender : int {
A = 1,
B = 2,
C = 3
};
基础类型的作用域和规范是正交的。
或者,如果您只想定义一些操作,而枚举通常保持强类型,您可以重载适当的运算符来实现
int operator<<(MsgType, int); // etc
But if I would not want them to be convertible, why would i specify the type to be int
保证一定的布局。遵循特定的 ABI。允许向前声明类型。
类型安全是使用新作用域枚举的主要原因(也许名称有点误导)。如果你只想要一个有范围的枚举并且可以隐式转换为整数,你可以将它包装在结构或命名空间中:
struct MsgSender {
enum Values {
A = 1,
B = 2,
C = 3
};
};
缺点是类型现在是 MsgSender::Values
,但值是 MsgSender::A
等
对于范围枚举,您必须 static_cast
到 std::underlying_type<MsgSener>
才能获得整数。
您可以通过 static_cast.
显式转换它们 int id = (static_cast<uint32_t>(MsgType::Input) << 16) + (static_cast<uint32_t>(MsgSender::A)) ;
您不能将 c++11 作用域枚举直接用作 int,但可以将其转换为 int
。
主要是因为类型安全的原因,unscoped enum 可以在 enums 内部泄漏名称,而 scoped enum 没有泄漏名称的风险,名称只能在内部可见。
目前c++中有2种枚举。
C++98 风格的无作用域枚举:
enum Color {Red, Green, Yellow};
,
可以隐式转换为 int.
C++11 作用域枚举:enum class{Red, Green, Yellow};
,
不能隐式转换为int,只能使用强制转换为其他类型,如static_cast<int>(my_color)
.
与非作用域枚举相比,作用域枚举有 3 个优势:
- 减少命名空间污染;
- 强类型安全;
- 范围内的枚举可以前向声明,非范围内的枚举需要额外的工作才能前向声明;
同时,无范围枚举比范围枚举更灵活。
作用域枚举和非作用域枚举都支持底层类型的规范,作用域枚举的默认底层类型是int
。 Unscoped enums 没有默认的底层类型,依赖于编译器,可以是 char
或 int
,根据值的范围。
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 项:优先使用作用域枚举而不是非作用域枚举。