如果枚举标签与类型不匹配,编译器是否应该发出警告?

时间:2011-11-17 11:23:04

标签: c++

我希望编译器发出如下警告:

“香蕉不是一种颜色。”

据我所知,在switch语句的上下文中,标签被提升为int,编译器对0感到满意,并不关心它是“Green”还是“Banana”。

我希望 - GCC的转换可以解决问题。

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;
}

2 个答案:

答案 0 :(得分:16)

强类型枚举:

C ++ 11使用enum

引入强类型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:错误:无法将'(Fruit)0'从'Fruit'转换为   '颜色'

注意:enum class不会导致GreenBanana再次出现在封闭的命名空间中,因此您必须明确写入Color::Fruit::现在,但你得到了类型安全。


C ++ 03中的警告问题

我认为在C ++ 03中对此的警告没有多大意义,它基本上只会变成噪音。

人们经常使用enum作为编译时常量,即使对于比特字段这样的事情也是如此。要使警告有意义,您必须抓住enum { foo=0xf }; int c = foo;之类的内容,并且许多代码库分散在int / enum次转换中。 (允许这样做会破坏任何更强类型检查的要点)。

更糟糕的是,enum几乎用于任何类型的元编程上下文,其中匿名enum不仅可以定期与int类型自由交替使用:

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 };
};

为了引入一种在C ++中enum class的当前状态添加类型安全性的非破坏性方法,需要enum的原因之一。现有代码会发出很多警告,因为像这样的事情,警告旁边就会没用。

即使在您展示的相当简单的switch语句示例中,这样的内容也是合法的:

#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&lt; - &gt; enum转换任何地方,它实际上意味着严格关于enum的类型后来变得毫无意义。在一般情况下,您无法检测是否发生了这种转换(可能是在不同的翻译单元中)。

到目前为止,{p> enum class是最好的方式,可以干净地引入这种严格性,而不会对现有代码产生负面影响。

答案 1 :(得分: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