2012-07-06 156 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