强类型枚举:
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 '。 –