未查封的枚举是否仍然有用?

voi*_*ter 6 c++ enums c++11

我没有在C++ 11标准中找到任何说明未编写的枚举被弃用的措辞,但从实用的角度来看,我想知道它们是否仍然有用.我团队中的很多人都养成了将未打包的枚举转换为范围内容的习惯,但这引起了一些麻烦:

class foo
{
public:
    enum MyEnum { One, Two, Three };
};
Run Code Online (Sandbox Code Playgroud)

他们将此转换为:

class foo
{
public:
    enum class MyEnum { One, Two, Three };
};
Run Code Online (Sandbox Code Playgroud)

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

  1. 如果转换为作用域枚举,则将其移出类并进入全局作用域或命名空间作用域(以提高可用性并避免上面的后一个用法示例).
  2. 如果你保持enum unscoped,请确保它在namespace/class/function/etc范围内,以便它不与其他名称冲突.

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

所有这些似乎都过于复杂化,并且将枚举已经存在于类中作为未编组的枚举似乎要简单得多.什么是决定两者之间的一般最佳实践方法?

Yak*_*ont 6

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

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

你可以覆盖operator|etc以保持所有"in type",或让它们生成底层类型 - 但是你的一个元素enum class不能隐式转换为uint32_t.

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

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

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


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

这是我为enums 找到的最常见的用例- 一个值列表,其基础类型和值仅仅是一个实现细节.