2012-07-06 198 views
6

让我们一码构造是我最近在项目的某个地方找到:枚举值碰撞枚举名

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 

为什么这样的混淆允许?我明白为什么必须预先加入enum关键字,所以编译器清楚地知道我声明了一个给定枚举的变量,而不是在同一个命名空间中使用其他枚举的值。我只是不明白为什么首先它甚至有可能做出这样的建设。

+0

我想这是编译器定义的,因为在Ideone代码导致错误:http://ideone.com/4GDTF – tinman 2012-07-06 14:06:21

+0

这就是为什么我已经放在GCC但据我所知VC还允许这样的建筑 – 2012-07-06 14:08:27

+0

@Kamil您可能希望改变NiceEnum的枚举常量的名称,因为你从CoolEnum复制它并且它们发生冲突。 – 2012-07-06 21:38:58

回答

7

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代码根本不会编译。这就是为什么要引入枚举类的原因,以便不打破向后兼容性。

+1

很高兴知道,但它不是给定问题的答案。我很高兴,在C++ 11他们清理出来的东西,但我只是想知道,为什么在第一个地方有可能 – 2012-07-06 14:06:29

+0

我放在命名空间外相同的结构,仍然是完全合法的C++ – 2012-07-06 14:14:33

+0

我不不要理解你指的是什么,你能扩展还是提供一个例子? – mfontanini 2012-07-06 14:16:54

1

答案是因为该标准要求这种行为。见3.3.7/2:

类名(9.1)或枚举名称(7.2)可通过名称的对象,功能,或在相同的范围内声明枚举的 被隐藏。如果 类或枚举名称和一个对象,功能,或枚举在相同的范围具有相同名称声明(以任何次序) ,所述 类或枚举名称是隐藏的任何地方对象,功能,或 枚举名是可见的。

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

至于你的情况,至少用g ++可以用typename来表示你想用类型而不是枚举器(typename Test::CoolEnum cEnum = Test::NiceVal1;)。

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

+1

“typename Test :: CoolEnum”不正确 - GCC恰好接受[但应拒绝](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48920)。改为使用“enum Test :: CoolEnum”。 – 2012-07-06 21:35:55