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

Edd*_*onk 10 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;
}
Run Code Online (Sandbox Code Playgroud)

Fle*_*exo 16

强类型枚举:

C++ 11引入了强类型enums,使用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;

}
Run Code Online (Sandbox Code Playgroud)

此代码将完全按照您的意愿失败:

test.cc:18:17:错误:无法将'(Fruit)0'从'Fruit'转换为'Color'

注意:enum class不会导致GreenBanana进入封闭的命名空间,所以你必须明确地写Color::,Fruit::现在,但你得到类型安全.


C++ 03中的警告问题

我不认为C++ 03中对此的警告会有很大意义,它基本上只会变成噪音.

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

更糟糕的是enum,几乎在任何类型的元编程上下文中都会使用它,其中匿名enums不仅可以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;
}
Run Code Online (Sandbox Code Playgroud)

但它们也被递归地用作本地存储:

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 };
};
Run Code Online (Sandbox Code Playgroud)

这是为什么enum class需要引入一种enum在C++ 当前状态下添加类型安全性的非破坏性方法的部分原因.现有代码会发出如此多的警告,由于这样的事情,警告旁边是无用的.

即使在您展示的相当简单的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;
}
Run Code Online (Sandbox Code Playgroud)

虽然这在这里是合法的,但它并没有太大的意义,但是像这样的东西仍然使用相当规律和有意义的"bit-twiddling"C代码.这个例子的要点是,通过在任何地方允许一个int< - > enum转换,它实际上意味着对enum后面的类型的严格限制变得毫无意义.在一般情况下,您无法检测是否发生了这种转换(它可能位于不同的翻译单元中).

enum class 到目前为止,这是彻底引入这种严格性的最好方法,而不会对现有代码产生负面影响.


Sil*_*ker 6

在C++ 11(新的C++标准)中,您可以使用它enum class来创建强类型枚举.请参阅有关C++ 11维基百科文章.

例:

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

// Put your main here - it would now fail
Run Code Online (Sandbox Code Playgroud)