【问题标题】:Are unscoped enumerations still useful?无范围的枚举仍然有用吗?
【发布时间】:2014-12-05 16:38:11
【问题描述】:

我没有在 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,我们没有将它们放在类中,否则会增加一些冗长的间接性。

所有这一切似乎都过于复杂了,而且将已经存在于类中的枚举保留为无作用域的枚举似乎要简单得多。在两者之间做出决定的一般最佳实践方法是什么?

【问题讨论】:

  • 切换到enum class 的好处是你可以读到关于为什么添加它的所有信息;切换到enum class 的缺点是您在上面写的所有内容。但是,这并没有告诉我们从头开始编写代码时应该做什么。
  • 第二次使用有什么问题?
  • @Daniel Verbosity。这就像为您的对象使用 2 个嵌套命名空间,而只有 1 个就足够了。
  • “只是将已经存在于类中的枚举保留为无范围的枚举”——这有时是明智的,有时不是。如果你想在同一个类中有两个枚举怎么办?
  • @MORTAL:如果你 static_casting 你的作用域枚举,那么你完全错过了重点,你的代码是错误的。

标签: c++ c++11 enums


【解决方案1】:

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

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

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

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

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

下一步可能是对这些值使用作用域枚举,但必须一次完成所有事情的开销可能意味着可能不会采取第一步。完美是善的敌人。


另一方面,如果您的枚举实际上只是一组枚举值,并且它们在基础类型中的值并不重要,那么作用域枚举几乎总是比无作用域枚举更好的主意。它们可以防止意外转换为基础类型:如果基础类型中的值仅仅是一个实现细节,那么这种转换可能会导致错误。

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

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多