c++ - 无作用域枚举是否仍然有用?

标签 c++ c++11 enums

我在 C++11 标准中没有发现任何表示不推荐使用无范围枚举的措辞,但从实用的角度来看,我想知道它们是否仍然有用。我团队中的很多人都养成了将无作用域枚举转换为有作用域枚举的习惯,但这引起了一些头痛:

class foo
{
public:
    enum MyEnum { One, Two, Three };
};

他们将其转换为:

class foo
{
public:
    enum class MyEnum { One, Two, Three };
};

这意味着当使用这些枚举器时,它看起来像 foo::MyEnum::One 而不是 foo::One。我一直在询问以下最佳实践:

  1. 如果您转换为作用域枚举,请将其移出类并移至全局作用域或命名空间作用域(以提高可用性并避免上述后一种用法示例)。
  2. 如果您不限制枚举的范围,请确保它在命名空间/类/函数/等范围内,这样它就不会与其他名称冲突。

这两点之间的主要区别在于,对于#1,我们没有将它们放在类中,否则会增加一些冗长的间接访问。

所有这些看起来都过于复杂了,而且似乎将类中已有的枚举作为无范围枚举保留起来会简单得多。在两者之间做出决定的一般最佳做法是什么?

最佳答案

作用域枚举数不能隐式转换为它们的基础类型。如果您需要将枚举值隐式转换为其基础类型,则不能使用作用域枚举器。

这很有用的一个例子是当您与不受控制的 API 通信时,您的枚举值是位标志。需要 uint32_t 或其他整数类型作为位标志的 API(您无法控制)。

您可以覆盖 operator| 等以保持所有内容“符合类型”,或者让它们生成基础类型——但您的枚举类的单个元素不能隐式转换为 uint32_t

我发现无范围的 enum 的另一个用途是替换 #define FOO 32 样式的宏。我得到的不是文本替换,而是具有相同含义的标记,而且我不必重写代码库。如果有一组紧密分组的此类值,我最终可以更改 int 参数,这些参数期望使用 #define 标记传递 enum 值,现在输入参数!

这允许逐步迁移到更好的代码库。

下一步可能是对这些值使用范围枚举,但必须一次完成所有操作的开销可能意味着第一步可能无法执行。完美是优秀的敌人。


另一方面,如果您的枚举实际上只是一组枚举值,并且它们在底层类型中的值并不重要,那么范围内的枚举几乎总是比非范围内的枚举更好的主意。它们可防止意外转换为基础类型:如果基础类型中的值仅仅是实现细节,则此类转换可能会导致错误。

这是迄今为止我为 enum 找到的最常见的用例——一个可区分值的列表,其基础类型和值只是一个实现细节。

关于c++ - 无作用域枚举是否仍然有用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27320603/

相关文章:

c++ - 为什么 std::set 似乎强制使用 const_iterator?

c++ - “嵌套”模板 `>>` 问题已解决。 `<::` 呢?

c++ - 前向声明 : incomplete type 'enums::Category' used in nested name specifier 有问题

c++ - 相同输入的 boost sha1 和 openssl 库的不同输出

c++ - 为什么编译器不报错?

c++ - 展开恒定数量的论点

c++ - 如何使用 boost 从 C++ 中的 json 中读取枚举?

c++ - strstream中的pcount和freeze用什么代替?

c++ - std::function 性能与模板相比

c++ - 枚举和定义语句之间的区别