C++17、C++20 和 C++23 中枚举类(enum class)的改进
本文回顾了C++17、C++20和C++23标准中针对**枚举类(enum class)**引入的一系列增强功能,旨在提升代码的安全性、可读性和可维护性。
1. 枚举类回顾
枚举类(作用域枚举)提供了类型安全的方式来定义一组命名常量。与传统枚举不同,枚举类不会隐式转换为整数或其他类型,从而防止意外误用。
// 枚举类:类型安全,无隐式转换
enum class Color { Red, Green, Blue };
Color c = Color::Red;
// int i = c; // 错误:无法转换
2. C++17:支持从底层类型的花括号初始化
C++17(P0138)允许使用花括号初始化从底层类型直接初始化枚举类,增强了灵活性,同时保持了类型安全。
enum class Handle : uint32_t { Invalid = 0 };
Handle h { 42 }; // OK,C++17起允许
// process({10}); // 错误:仍需显式类型
process(Handle{10}); // 正确
此前,这需要使用 static_cast。C++17的改进在提供便利的同时,通过仅允许显式花括号初始化保持了安全性。
3. C++20:using enum 声明
C++20引入了 using enum 语法,允许将枚举类的所有枚举项引入当前作用域,而不会丧失作用域枚举的类型安全优势。这显著减少了代码冗余,尤其在 switch 语句或频繁使用枚举项的场景中。
enum class ComputeStatus { Ok, Error, FileError /* ... */ };
// 使用前需重复限定名
switch (s) {
case ComputeStatus::Ok: /* ... */
case ComputeStatus::Error: /* ... */
}
// 使用 using enum 后简化
switch (s) {
using enum ComputeStatus;
case Ok: /* ... */ // 无需再写 ComputeStatus::
case Error: /* ... */
}
此特性使代码更清晰、简洁,且不牺牲类型安全。
4. C++23:std::to_underlying 工具函数
C++23标准化了 std::to_underlying 函数,用于将枚举值转换为其底层整数类型。这解决了与存储、比较或互操作 API 对接时的常见需求,使转换更直接、更具表现力。
enum class Permissions : uint8_t { Execute = 1, Write = 2, Read = 4 };
// C++23之前
uint8_t val = static_cast<uint8_t>(Permissions::Read);
// C++23
auto val = std::to_underlying(Permissions::Read); // 更简洁,意图明确
该函数提升了代码可读性,减少了样板代码。
5. 未来展望:C++26 反射
未来可能通过C++26的反射特性(提案P2996)进一步支持枚举,例如将枚举值转换为字符串。目前可通过第三方库(如 magic_enum)实现类似功能。
总结
C++17至C++23对枚举类的改进包括:
- C++17:允许从底层类型进行花括号初始化。
- C++20:引入
using enum 以简化枚举项的使用。
- C++23:提供
std::to_underlying 方便底层值的获取。
这些增强在保持类型安全的前提下,提高了枚举类的灵活性、可读性和实用性。