Effective Modern C++ 条款10:优先考虑限域enum而非未限域enum

在软件开发中,优先使用限域enum(enum class)而非未限域enum(C++98风格的enum)是一个明智的选择。以下是详细的建议:

  1. 避免命名冲突
    未限域enum的枚举名会泄漏到其所在的作用域,导致命名冲突。例如:
enum Color { black, white, red };
auto white = false; // 错误,white已经被声明

而限域enum的枚举名仅限于其内部作用域:

enum class Color { black, white, red };
auto white = false; // 正确,white属于外部作用域
  1. 强类型检查
    限域enum的枚举名不会隐式转换为整数,防止了意外的类型转换:
enum class Color { black, white, red };
Color c = Color::red;
if (c < 14.5) { // 错误,无法比较Color和double
}

需要显式转换:

if (static_cast<double>(c) < 14.5) { // 显式转换
}
  1. 支持前置声明
    限域enum可以被前置声明,减少编译依赖:
enum class Status; // 前置声明
void process(Status s); // 使用前置声明

即使Status的定义发生变化,包含前置声明的头文件不需要重新编译。

  1. 指定底层类型
    限域enum默认底层类型为int,可以指定其他类型:
enum class Status : std::uint32_t { ... };

未限域enum在C++11中也可以指定底层类型,但限域enum在这一点上更为灵活和直观。

  1. 特殊情况下的使用
    在某些情况下,如使用std::tuple时,未限域enum可能更方便,因为其枚举名可以直接作为索引:
enum UserInfoFields { uiName, uiEmail, uiReputation };
UserInfo uInfo;
auto val = std::get<uiEmail>(uInfo); // 直接使用枚举名

限域enum则需要显式转换:

enum class UserInfoFields { uiName, uiEmail, uiReputation };
auto val = std::get<static_cast<std::size_t>(UserInfoFields::uiEmail)>(uInfo);

可以通过编写constexpr函数来简化:

template<typename E>
constexpr auto toUType(E enumerator) noexcept {
    return static_cast<std::underlying_type_t<E>>(enumerator);
}
auto val = std::get<toUType(UserInfoFields::uiEmail)>(uInfo);

总结
限域enum在大多数情况下优于未限域enum,尤其是在避免命名冲突、防止隐式类型转换和提高代码维护性方面。尽管在某些特定场景下使用未限域enum可能更方便,但限域enum的灵活性和安全性使其成为更优的选择。在实际开发中,应优先考虑使用限域enum,除非有特殊需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值