強類型枚舉:
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
不會引起Green
和Banana
是在封閉命名空間了,所以你必須明確地寫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
是迄今爲止乾淨地引入這種嚴格而對現有代碼的不利影響的最好的方式。
哪個編譯器? – FailedDev
在C++ 11的6.4.2中沒有必要的診斷,如果這就是「編譯器給出警告?」的意思。所以你問的問題的答案是「否」,但是也許你想問的問題是「是否有編譯器可以啓用這樣的警告,如果是的話,怎麼樣?」 ;-) –
哦,並且「標籤被提升爲int」 - 並不那麼簡單。標籤被轉換爲'c'的提升類型,至少是'int','int'對於你定義的枚舉來說足夠了,但它可以是其他類型,比如'unsigned int'或'long long '。 –