enum class与enum(uint8_t)使用位运算符为何编译结果不同?
问题描述
我编写了如下代码:
enum class MouseState : uint8_t { kLeft = 0x01, kRight = 0x02, kMiddle = 0x04, }; uint8_t mouseState { 0 }; if ((mouseState & MouseState::kLeft) != 0) { std::cerr << "okay\n"; }
编译时出现如下错误:
error: invalid operands to binary expression ('uint8_t' (aka 'unsigned char') and 'MouseState') if ((mouseState & MouseState::kLeft) != 0) { ~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
但如果移除class关键字,使用普通枚举定义:
enum MouseState : uint8_t { kLeft = 0x01, kRight = 0x02, kMiddle = 0x04, };
则编译正常(使用C++20标准与clang编译器)。请问这是为什么?
原因解析
这事儿的本质是普通枚举(enum)和强类型枚举(enum class)的设计差异:
普通枚举的枚举值会自动隐式转换成它的底层整数类型(这里就是
uint8_t)。所以你写mouseState & MouseState::kLeft时,MouseState::kLeft会悄悄转成uint8_t,和mouseState类型对上,按位与操作自然合法。强类型枚举(
enum class)从设计上就主打强类型隔离,它不会自动转成整数类型。MouseState::kLeft的类型是MouseState,而mouseState是uint8_t,两种完全不同的类型不能直接做按位与,编译器当然要报错。
如果想保留enum class的类型安全特性,同时完成这个操作,有两个常用办法:
- 手动把枚举值转成整数类型:
if ((mouseState & static_cast<uint8_t>(MouseState::kLeft)) != 0) { std::cerr << "okay\n"; }
- 给
enum class重载按位与运算符,让它支持和整数的操作(不过这么做会削弱强类型的隔离性,得按需使用)。
内容的提问来源于stack exchange,提问作者user18490
相关产品推荐
相关产品推荐

