一位同事和我在使用枚举时遇到了一种奇怪的行为。
我们正在使用相同的编译器(gcc 4.8.4)编译同一个项目,(大概)是相同的make文件。唯一的区别是我是一个Linux VM机器,他在原生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
Q1:解决枚举值的标准方法是什么?
Q2:编译器处理代码的方式会产生什么不一致? (我的猜测是我的同事在他的设置中使用了一些C ++ 11功能,但在开始研究他是如何启用它们之前我需要一些确认)
上面使用的代码用于显示我们面临的问题。
考虑到这是一个非常大的项目,使用了很多枚举,我们面临的情况是,一些开发人员使用第一种方式来解决枚举值,而另一些人则使用第二种方法。
第一种方法的好处是在自动完成期间仅列出来自限定枚举的值而不是整个命名空间中的值(例如第二种方法)。
考虑到命名空间中有许多枚举,为什么人们宁愿选择第一种方法也是有道理的。
答案 0 :(得分:1)
在C ++ 11之前的C ++中,枚举没有为其枚举器(常量)生成新的命名空间。您的原始代码行在旧C ++中无效,因为没有名称空间Something::Something
。这是将枚举放在其自己的命名空间中的一个很好的理由:替代和较旧的解决方案是在每个枚举器中放置枚举的名称,如
enum side {
SIDE_DARK,
SIDE_LIGHT
}
side s = SIDE_DARK;
C ++ 11引入了范围的枚举(a.k.a。强枚举),它的工作方式与原始代码的方式相同。要获得完整的强大枚举,您必须使用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之间的区别,那就有意义了,但是你已经在你的问题中排除了这种可能性。 (我只为未来的读者提及。)
由于这是一个大项目,您应该在编码标准或其他项目文档中设置您所定位的语言版本。如果您的目标是C ++ 11,那么您需要更新项目的编译器选项,以便编译原始代码(因为它是有效的C ++ 11)。如果您的目标是C ++ 03,那么编写第一个示例代码的人需要修复它而不是依赖于非标准选项或编译器扩展。
当然,如果您的目标是C ++ 11,而不使用强枚举,则可以选择是否将枚举名称用作命名空间。您可能希望在编码标准中指定此项,或者(更好)指定应尽可能使用强枚举。