2016-11-15 73 views
2

爲什麼不是這個有效的C++?:爲什麼我不能將枚舉作爲另一個枚舉的基礎類型?

enum foo : unsigned { first_foo, second_foo }; 
enum bar : foo { best_foo = first_foo }; 

GCC 5.4.0說:

/tmp/a.cpp:3:16: error: underlying type ‘foo’ of ‘bar’ must be an integral type 
    enum bar : foo { best_foo = first_foo }; 

我可以理解爲什麼如果foo是一個float,或者一些結構,我會得到這個錯誤,或什麼不是。但就語義,類型安全等而言,這對我來說似乎是完全合法的。我錯過了什麼?

+2

爲什麼?因爲標準如此說。 :) – Zereges

+0

@Zereges:[但...爲什麼?](https://cdn.meme.am/cache/instances/folder489/500x/59809489.jpg) – einpoklum

+1

通常的原因是[有人寫了一個提案] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf),他們提出的建議被接受。 –

回答

2

當您向C++添加東西時,您往往會添加解決問題的最小量。

enum A:int語法允許您指定enum A如何以整數形式存儲。這就是它所做的,它解決了這個問題。

enum A:B其中B是一個枚舉可能有很多含義。 A可以擴展BA可以是具有不同名稱的B基礎類型的子集,或A可以是嚴格限制爲具有可存儲在B內的值的子集或A可以是其值僅限於B值的「船體」。

其中,「相同的基礎類型」解決方案(使用:int語法)與enum A:std::underlying_type_t<B>對齊。所以已經有一種方法可以做到這一點,並且不是特別繁瑣。

直到有人提出了什麼enum A:B應該是什麼意思,並說服委員會足夠的建議,這是不可能被允許的。當有多種不同的合理含義時,這使得選擇任何一種含義變得更加困難。人們需要一個強有力的用例來說明爲什麼一個特定的含義是最好的,爲什麼值得把它放在標準中是值得的。

+0

那麼,如果你喜歡 - 你可以看看我的[使用案例](http://stackoverflow.com/q/40607928/1593077),並提示你是否在多大程度上引人注目。 – einpoklum

3

好了,不完全一樣,但我認爲你可以使用std::underlying_type

enum foo : unsigned { first_foo, second_foo }; 
enum bar : std::underlying_type_t<foo> { best_foo = first_foo }; 
+0

這是我正在使用的解決方法,但這不是我的問題... – einpoklum

+2

@einpoklum嗯,你沒有在你的問題中提到過,所以我怎麼可能知道?我不知道爲什麼它不能滿足你的需求,無論如何,常規的'enum'在底層類型轉換方面相當薄弱。 –

+1

我的問題是「爲什麼」,我寫了兩次,非常明確...... – einpoklum

7

C++ 11 [dcl.enum/2:

類型specifier-一個的enq enum-base應命名爲整型;任何cv資格都會被忽略。

枚舉本身不是整數類型– [basic.fundamental]/7:

類型boolcharchar16_tchar32_twchar_t和符號和無符號整數類型統稱積分類型。

這伴隨的非標準的腳註:

因此,枚舉不是積分;但是,枚舉可以像[conv.prom]中指定的那樣提升爲整型。

爲了實現我想你要找的效果,但是,仍然是簡單的:

enum bar : std::underlying_type<foo>::type { best_foo = first_foo }; 
+0

好吧,這是直接的形式原因 - 但爲什麼必須將類型說明符seq命名爲整型而不是整型或枚舉類型? – einpoklum

+0

@einpoklum:對於這類網站來說,這是一個深遠的問題。我不在C++委員會,所以我不知道我怎麼知道。 ; - ] – ildjarn

+0

那麼,有時候在委員會或者在其工作之後的人會經常訪問這個網站並回答問題。比亞恩甚至回答了我一次。 – einpoklum

3

對我來說這是一個邏輯上的錯誤說一個枚舉可以基於一個又一個枚舉。如果您認爲基礎是存儲枚舉中定義的值的存儲類型,則無法將其作爲邏輯表達式來表示存儲類型是枚舉。因爲枚舉不僅是存儲類型,而且還包含一組有效值。

如果我們可以寫類似:

enum A: int { ONE, TWO }; 

什麼應該是指:

enum B: A{}; 

由於A定義不僅墊層類型(我稱之爲存儲類型),而且一組有效的值,應該B只是枚舉A的一個子集,這意味着您只能定義已經在A中定義的值?

現在是否可以說我們已經將價值ONE,TWO定義在B中? 而且是現在可以添加多個值,如:

enum B: A{THREE}; 

和所有有效值現在一,二,三?

或者是意義,我們只得到子集:

enum B: A{ONE}; 

這意味着B只能使用A.已定義的值簡單,使得它很難對我做一個枚舉另一個枚舉的基礎。

如果你打開那扇門,你也可以想出你想要使用其他類型位域的底層存儲類型的想法。

struct A { unsigned int a : 3; unsigned int B: 2; }; 

應該再

enum B: A { ONE, TWO }; 

還有效嗎?我不相信! ;)

從邏輯上(我的觀點來看)enum的underlaying類型是它的存儲類型。將枚舉作爲另一個枚舉的底層存儲類型是沒有意義的。

+1

「應該只是枚舉A的一個子集」?是的,我真的會這麼想。 – einpoklum

+0

@einpoklum如果它只能是一個子集,則它是從結構/類派生出來的。因爲只能在派生類中擴展基類。那麼你倒轉枚舉的邏輯是否合乎邏輯? ;) – Klaus

+0

克勞斯:這是不正確的。繼承常常用於收縮基類而不是擴展它。你同時擁有「同一種類型」和「僅僅是類型之間」關係。 – einpoklum