c++ - 不一致的完全限定枚举编译时行为

标签 c++ gcc enums

我和一位同事在使用枚举时遇到了一个奇怪的行为。

我们都在使用(大概)相同的 make 文件和相同的编译器 (gcc 4.8.4) 编译同一个项目。唯一的区别是我是一台 Linux 虚拟机,而他在本地 Linux 环境中,但这不应该是问题的根源。

给定以下代码片段

namespace Something
{
      enum Something {
             DARK_SIDE,
             LIGHT_SIDE
      }
}

...

Something::Something leEnumVal = Something::Something::DARK_SIDE; // inconsistency here

不一致的是,在我的电脑上出现以下错误:

'Something::Something' is not a class or namespace

但是,在我的同事环境中一切正常。

值得一提的是,我们使用的是QT Creator,在构建过程中可能会产生一些额外的东西。

Ofc,我设法让代码在我的环境中编译,不一致的行变成了:

 Something:Something leEnumVal = Something::DARK_SIDE; // this compiles for both

问题 1:处理枚举值的标准方法是什么?

问题 2:什么会导致编译器处理代码的方式不一致? (我的猜测是我的同事在他的设置中使用了一些 C++ 11 特性,但在开始研究他如何启用它们之前我需要一些确认)

上面使用的代码用于显示我们面临的问题。

考虑到这是一个非常大的项目,使用了许多枚举,我们面临这样的情况:一些开发人员使用第一种方法来寻址枚举值,而另一些开发人员则使用第二种方法。

第一种方法的好处是在自动完成期间仅列出来自限定枚举的值,而不是来自整个命名空间的值(例如第二个)。

考虑到命名空间中有许多枚举,所以人们宁愿选择第一种方法也是有道理的。

最佳答案

在 C++11 之前的 C++ 中,枚举不会为其枚举器(常量)生成新的命名空间。您的原始代码行在旧 C++ 中无效,因为没有命名空间 Something::Something。这是将枚举放在它自己的命名空间中的一个很好的理由:另一种较旧的解决方案是将枚举的名称放在每个枚举器中,例如

enum side {
    SIDE_DARK,
    SIDE_LIGHT
}

side s = SIDE_DARK;

C++11 引入了scoped enums(又名strong enums),它按照您的原始代码所需的方式工作。要获得完整的强大枚举,您必须使用 enum class 专门请求它:

enum class side {
    DARK,
    LIGHT,
}

side s = side::DARK;

但为了友好起见,C++11 允许您在使用枚举器名称时使用命名空间表示法,无论您使用的是强枚举还是传统枚举。这支持您的猜测,即您的同事在他的 Makefile 或编译器选项中打开了 C++11,(例如使用 -std=c++0x-std=c++11)。

MSVC(也许还有其他编译器)有一个非标准扩展,允许您像使用命名空间一样使用枚举,即使在较旧的 C++ 版本中也是如此,所以如果这是 gcc 和 MSVC 之间的区别,那是有道理的,但是您已经在问题中排除了这种可能性。 (我只为 future 的读者提及它。)

由于这是一个大型项目,您应该在您的编码标准或其他项目文档中设置您的目标语言版本。如果您的目标是 C++11,那么您需要更新项目的编译器选项,以便编译原始代码(因为它是有效的 C++11)。如果您的目标是 C++03,任何像您的第一个示例那样编写过代码的人都需要修复它,而不是依赖非标准选项或编译器扩展。

当然,如果您的目标是 C++11,并且不使用强枚举,您可以选择是否将枚举名称用作命名空间。您可能希望在您的编码标准中指定这一点,或者(更好的是)指定应尽可能使用强枚举。

关于c++ - 不一致的完全限定枚举编译时行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33756453/

相关文章:

c++ - 使用 MFC 或 Win32 显示内存缓冲区中的所有位图类型

c++ - 指针模板数组 C++?

gcc - 对 libnuma 的 undefined reference

c++ - clang vs gcc 模板子类在父类中使用前向声明的类

c# - 数据绑定(bind)枚举 - 命名空间中不存在名称 'StoreLocation'

c++ - CURL SSH key 密码安全

c++ - 在 Visual Studio 中暂时禁用包含的编译警告

c++ - atomic<int>::fetch_add 的成本与 __sync_fetch_and_add

java - org.hibernate.Hibernate 枚举常量

c# - C# 中隐藏的枚举值