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

时间:2018-07-12 14:57:17

标签: c++ enums c++03

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

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之前。

有人可以看到为什么这样做吗? 事先道歉,如果答案真是微不足道。

编辑后添加:在内部类中使用。 (当枚举是全局枚举时,我们的样式指南要求条目以公共前缀开头,以便将它们与其他符号区分开。)

6 个答案:

答案 0 :(得分:5)

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

FooType m_type;
m_type = TypeA;

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

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,而不能将来自范围枚举的枚举数。因此,有了类中的定义,

int i = FooType::TypeA;

有效,并且i的值为0。使用范围限定的枚举无效。

在两种情况下,强制类型转换都可以:

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

答案 1 :(得分:3)

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

enum FooType
{
    TypeA,
    TypeB,
    Type_MAX
};

TypeATypeBType_MAX成为全局范围内的名称。这可能导致与其他enum或已经使用的其他名称发生冲突。通过将enum放在struct中,可以将名称限制为该结构的范围。完成此操作的另一种方法是使用namespace

C ++ 11提供了enum class,可将enum成员的范围限制在enum本身,因此,如果您可以处理更严格的控件{{1} }。

答案 2 :(得分:1)

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

TypeA可能只是为了避免每次都不键入完全限定的typedef类型名称。

这仅适用于C ++ 11之前的版本。 C ++ 11具有enum,它声明了作用域枚举。您提到此代码是在此之前编写的。

答案 3 :(得分:1)

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

结构在这里更像是一个名称空间。作者仍然可能希望枚举名称本身在外部命名空间中,这由typedef完成。

答案 4 :(得分:1)

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

在您的第二个示例中,我可以做到:

m_type = FooType::TypeA;

在原始示例中,您需要执行以下操作:

{{1}}

如果TypeA在您的应用程序中相当普遍,那么我可以理解为什么您不想污染其周围的名称空间。

答案 5 :(得分:0)

  

我的问题是,这样做有什么好处? (或者,这可以避免什么问题?)

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

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,
};

程序员本来可以使用名称空间,这可能更清楚了。