为什么将枚举放在结构中然后使用 typedef 名称?

Why put an enum in a struct and then use a typedef name?

我发现以下模式在我们公司的代码中使用得相当普遍。

struct Foo
{
    enum FType
    {
        TypeA,
        TypeB,
        Type_MAX
    };
};
typedef Foo::FType FooType;
[...]
FooType m_type;

我的问题是,这样做有什么好处? (或者,这避免了什么问题?) 明确地说,我想知道为什么他们不只是...

enum FooType
{
    TypeA,
    TypeB,
    Type_MAX
};
[...]
FooType m_type;

不能请原程序员,因为他们被重新分配了,原来我们公司指定的主题专家是我。

如果有帮助,此代码已在不同时间针对不同目标平台使用多个版本的 MSVC、gcc 和 clang 进行编译...都是 C++11 之前的版本。

谁能看出为什么要这么做? 如果答案是微不足道的,请提前致歉。

编辑补充:这个用在里面 类。 (当枚举是全局的时,我们的风格指南要求条目以公共前缀开头,以便将它们与其他符号区分开来。)

在 C++11 之前的版本中,您应该始终将 enum 放在 struct(或 class)中。这样做的原因是它防止了全局 namespace 的污染,并且在使用结构的成员时强制使用限定名称。即 Foo::TypeA。为什么?因为否则其他人可能会决定在代码中的其他地方创建一个常量或另一个名为 TypeAenum 成员,并且会出现名称冲突。

typedef可能只是为了方便,不用每次都输入完全限定的enum类型名称。

这仅适用于 C++11 之前的版本。 C++11 有 enum class 声明一个范围枚举。你提到这段代码是在那之前写的。

这样做很可能是为了防止 enum 成员污染全局范围。当你有

enum FooType
{
    TypeA,
    TypeB,
    Type_MAX
};

TypeATypeBType_MAX 成为全局范围内的名称。这可能会导致与其他 enum 或其他已在使用的名称发生冲突。通过将 enum 放在 struct 中,您可以将名称限制在结构的范围内。另一种实现方式是使用 namespace.

C++11 提供 enum class 使 enum 成员的范围限定在 enum 本身,因此如果您可以处理更严格的控制 enum class 强加。

编写此代码时 C++ 中可能没有 enum class,因此这是避免外部命名空间污染的唯一解决方案。

Struct在这里更像是一个命名空间。作者仍然可能希望枚举本身的名称位于外部命名空间中,这是由 typedef.

完成的

在旧的 C++ 版本中,枚举名称被添加到周围的命名空间中。

在你的第二个例子中我可以这样做:

m_type = TypeA;

在原来的例子中你需要做的是:

m_type = FooType::TypeA;

如果 TypeA 在您的应用程序中相当常见,我明白您为什么不想污染它周围的命名空间。

普通旧枚举的感知问题是枚举数成为定义枚举的范围内的名称。因此,您可以说,例如,

FooType m_type;
m_type = TypeA;

如果您还定义了一个 class 名称 TypeA,就会发生冲突。将枚举放在 class 中意味着您必须使用范围限定符来获取名称,这将消除冲突。这也意味着你必须写

FooType m_type;
m_type = FooType::TypeA;

因为以前的版本无效。

此问题的更新解决方案是范围枚举:

enum class FooType {
    TypeA,
    TypeB,
    Type_MAX
};

现在你可以说

FooType m_type;
m_type = FooType::TypeA;

但不是

m_type = TypeA;

这里的一个区别,正如@Jarod42 指出的那样,由普通枚举定义的枚举器可以隐式转换为 int,而作用域枚举中的枚举器则不能。所以在 class,

里面定义
int i = FooType::TypeA;

有效,并且 i 获得值 0。对于作用域枚举,它无效。

在这两种情况下,强制转换都可以进行转换:

int i = static_cast<int>(FooType::TypeA);

My question is, what is the benefit of this? (Or, what problem does this avoid?)

它将单个枚举标识符限制在class的命名空间中:

int TypeA;

struct Foo
{
    enum FType
    {
        TypeA, // OK, Foo::TypeA does not conflict with ::TypeA
        TypeB,
        Type_MAX,
    };
};

enum FooType
{
    TypeA, // not OK, conflicts with the existing ::TypeA declaration
    TypeB,
    Type_MAX,
};

程序员本可以改用命名空间,这样可能更清晰。