2011-11-17 30 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

不,不要紧,“枚举类型”明确允许作为转换目标。 :) –

相关问题