由于其自身的范围,我想将旧式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:二进制'<<':未找到采用'MyClass :: MsgType'类型的左操作数(或没有可接受的转换)的运算符
这对我来说似乎有点不合逻辑。
编辑:
我完全意识到抛弃他们的可能性。但是,如果我不希望它们可转换,为什么要将类型指定为int
。特别是如果语法建议使用某种“从int
继承的”
答案 0 :(得分:6)
这就是功能。作用域枚举不能隐式转换为整数,因此您不能使用它们代替整数。它们是按设计强烈键入的。如果想要隐式转换,请使用无作用域枚举。
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。允许向前声明类型。
答案 1 :(得分:2)
类型安全性是使用新的作用域枚举的主要原因(也许名称有点误导)。如果只需要一个有范围的枚举并且可以隐式转换为整数,则可以将其包装在struct或命名空间中:
struct MsgSender {
enum Values {
A = 1,
B = 2,
C = 3
};
};
缺点是类型现在为MsgSender::Values
,但值是MsgSender::A
等。
对于有作用域的枚举,您必须static_cast
到std::underlying_type<MsgSener>
才能获得整数。
答案 2 :(得分:2)
您可以通过static_cast显式转换它们。
int id = (static_cast<uint32_t>(MsgType::Input) << 16) + (static_cast<uint32_t>(MsgSender::A)) ;
答案 3 :(得分:1)
您不能将c ++ 11范围内的枚举直接用作int,而是可以将其强制转换为int
。
主要是出于类型安全的原因,无范围的枚举可以泄漏枚举内部的名称,而作用域限定的枚举没有泄漏名称的风险,名称只能在内部隐匿。
到目前为止,c ++中有两种枚举。
C ++ 98风格的无作用域枚举:
enum Color {Red, Green, Yellow};
,
可以隐式转换为int。
C ++ 11范围内的枚举:enum class{Red, Green, Yellow};
,
不能隐式转换为int,只能使用强制转换将其转换为其他类型,例如static_cast<int>(my_color)
。
与未限制范围的枚举相比,范围枚举的枚举具有3个优势:
与此同时,无作用域的枚举比作用域枚举更灵活。
作用域枚举和未作用域枚举都支持基础类型的规范,作用域枚举的默认基础类型为int
。未作用域的枚举没有默认的基础类型,它取决于编译器,根据值的范围可以是char
或int
。
enum class Color: std::uint8_t{Red, Green, Yellow}; // Definition
enum Color: std::uint8_t{Red, Green, Yellow}; // Forward Declaration
仅当ther声明分隔基础类型时,才可以向前声明未作用域的枚举。
在实践中,有范围的枚举比无范围的枚举更重要。
请参阅Scott Meyers撰写的“ Effective Modern C ++”一书,第10项:与无范围的枚举相比,更喜欢范围枚举。