2011-11-17 21 views
10

我希望編譯器給出如下警告:如果枚舉標籤與類型不匹配,編譯器是否應該發出警告?

「香蕉不是顏色。」

我明白,在switch語句的上下文中,標籤被提升爲int,編譯器對0感到滿意,並且不在乎它是「綠色」還是「香蕉」。

我希望 - 海灣合作委員會的轉換將做的伎倆。

enum Color 
    { 
    Green = 0 
    }; 

enum Fruit 
    { 
    Banana = 0 
    }; 

int main() 
{ 
    Color c = Green; 
    switch (c) 
    { 
    case Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 
} 
+0

哪個編譯器? – FailedDev

+3

在C++ 11的6.4.2中沒有必要的診斷,如果這就是「編譯器給出警告?」的意思。所以你問的問題的答案是「否」,但是也許你想問的問題是「是否有編譯器可以啓用這樣的警告,如果是的話,怎麼樣?」 ;-) –

+4

哦,並且「標籤被提升爲int」 - 並不那麼簡單。標籤被轉換爲'c'的提升類型,至少是'int','int'對於你定義的枚舉來說足夠了,但它可以是其他類型,比如'unsigned int'或'long long '。 –

回答

17

強類型枚舉:

C++ 11引入了強類型enum S,使用enum class

#include <iostream> 

enum class Color 
    { 
    Green = 0 
    }; 

enum class Fruit 
    { 
    Banana = 0 
    }; 


int main() { 
    Color c = Color::Green; 
    switch (c) 
    { 
    case Fruit::Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 

} 

,你希望這段代碼究竟失敗:

test.cc:18:17: error: could not convert '(Fruit)0' from 'Fruit' to 'Color'

注:enum class不會引起GreenBanana是在封閉命名空間了,所以你必須明確地寫Color::Fruit::現在,但你也得到的類型安全。


中的警告的問題C++ 03

我不認爲這個警告在C++ 03將太大的意義,它將基本上只是成爲噪音。

人們經常使用enum作爲編譯時常量,即使對於比特字段也是如此。爲了讓警告變得有意義,您必須抓取諸如enum { foo=0xf }; int c = foo;之類的東西,並且許多代碼庫分散了int/enum轉換。 (允許這將打敗任何更強大的類型檢查)。

更糟

但仍然會在幾乎任何類型的元編程方面,其中匿名enum s的不僅是自由與int類型定期交替使用的使用enum S:

template <int I> 
struct is_odd { 
    enum { value = !(I % 2) }; 
}; 

template <int I> 
struct foo { 
    static void bar() { /* I is true */ } 
}; 

template <> 
struct foo<0> { 
    static void bar() { /* I is false */ } 
}; 

int main() { 
    foo<is_odd<201>::value>::bar(); 
    int i = is_odd<200>::value; 
} 

但他們還使用遞歸作爲本地存儲:

template <int N> 
struct factorial { 
    enum { 
     // This enum is *not* compatible with the one in N-1 
     value = N * factorial<N - 1>::value 
    }; 
}; 

template <> 
struct factorial<0> { 
    enum { value = 1 }; 
}; 

這就是爲什麼爲了引入插件的非中斷的方式被要求enum class有一部分原因g在C++中的當前狀態enum s中的類型安全性。現有代碼會有如此多的警告,因爲這樣的事情,警告將會變得無用。

即使你表現出相當簡單的開關語句示例,這樣的事情是合法的:

#include <iostream> 
enum Color { Green = 0x1, Red = 0x2 }; 
enum Fruit { Banana = 0x3 }; 

int main() { 
    int v = Green|Red; 
    Color c = Color(v); 
    switch (c) { 
    case Banana: 
    std::cerr << "Banana" << std::endl; 
    break; 
    } 
    return 0; 
} 

雖然這是合法的在這裏它不是巨大的意義,但是這樣的事情是相當定期和有意義的使用「 bit-twiddling「C代碼仍然存在。這個例子的要點是,通過允許一個int <->enum轉換任何地方它實際上意味着對後面的enum的類型嚴格是沒有意義的。在一般情況下,您無法檢測是否發生了這種轉換(可能位於不同的翻譯單元中)。

enum class是迄今爲止乾淨地引入這種嚴格而對現有代碼的不利影響的最好的方式。

+0

我想你在這裏添加了一些有效的觀點,但我不明白爲什麼在switch語句的上下文中的警告不會有用。 –

+0

@EddyPronk - 我做了另一個編輯,我希望說明爲什麼只是允許int-> enum轉換會導致這樣的警告無益。 – Flexo

+0

我喜歡'enum class',但是在現實生活中使用C++ 11特性需要數年的時間。您添加了更多與轉化有關的信息,但這與我所詢問的具體情況無關。同樣,在switch語句的特定上下文中,警告我們打開類型Color並具有Fruit類型的案例標籤這一事實是有意義的。應該有足夠的上下文來警告這裏可疑的事情。 –

6

在C++ 11(新的C++標準)中,您可以使用enum class來創建一個強類型的枚舉。請參閱Wikipedia article on C++11

例子:

enum class Color { Green }; 
enum class Fruit { Banana }; 

// Put your main here - it would now fail 
+0

請問開關甚至現在的工作?我猜不是。 –

+0

不,不要緊,「枚舉類型」明確允許作爲轉換目標。 :) –

相關問題