枚举值与枚举名称冲突

Enum value collision with enum name

本文关键字:枚举 冲突      更新时间:2023-10-16

让我们以我最近在项目中的某个地方找到的代码结构为例:

namespace Test
{
    enum EName
    {
        CoolEnum,
        NiceEnum
    };
    enum CoolEnum
    {
        CoolVal1,
        CoolVal2
    };
    enum NiceEnum
    {
        NiceVal1,
        NiceVal2
    };
}

我的问题是为什么编译器允许这样的事情。让我们在这里看一个代码示例:

Test::CoolEnum cEnum = Test::NiceVal1; // INVALID, as compiler refers to Test::CoolEnum value of Test::Ename enum

为什么允许这种混乱?我理解为什么我必须在前面加上枚举关键字,所以编译器清楚地知道我正在声明给定枚举的变量,而不是在同一命名空间中使用其他枚举的值。我只是不明白为什么首先甚至可以进行这样的结构。

C++11 的枚举类是解决方案:

namespace Test
{
    enum class EName
    {
        CoolEnum,
        NiceEnum
    };
    enum class CoolEnum
    {
        NiceVal1,
        NiceVal2
    };
    enum class NiceEnum
    {
        NiceVal1,
        NiceVal2
    };
}

然后,您可以使用适当的NiceVal1

Test::CoolEnum cEnum = Test::CoolEnum::NiceVal1;

普通枚举是从 C 继承而来的,其中没有命名空间的概念。如果纯枚举引入了某种命名空间,则使用枚举的 C 代码根本不会编译。这就是引入枚举类的原因,以免破坏向后兼容性。

答案是因为标准规定了这种行为。参见 3.3.7/2:

类名 (9.1) 或枚举名 (7.2) 可以通过名称隐藏 在同一作用域中声明的对象、函数或枚举器。如果 类或枚举名称以及对象、函数或枚举器是 在同一范围内(以任何顺序)声明,具有相同的名称, 类或枚举名称隐藏在对象、函数或 枚举器名称可见。

据推测,这是为了促进与 C 的机制(枚举器不会打开新范围)的兼容性,该机制已经建立了很长时间。

在您的情况下,至少使用 g++ 您可以使用 typename 来指示您想要使用类型而不是枚举器 ( typename Test::CoolEnum cEnum = Test::NiceVal1; )。

但是,一般来说,我喜欢将所有枚举的范围限定在单独的命名空间或类中,以完全防止这些冲突。