在switch条件中从类隐式转换为枚举类型

时间:2014-08-05 16:26:58

标签: c++ c++11 switch-statement language-lawyer implicit-conversion

g ++ 4.9.0接受以下代码:

enum E { foo };

struct C {
  operator E() const { return foo; }
  operator E() { return foo; }
};

int main() {
  C c;
  switch (c) {
    case foo: break;
  }
}

但是clang 3.4.1通过以下诊断拒绝它:

12 : error: multiple conversions from switch condition type 'C' to an integral or enumeration type
switch (c)
^ ~
5 : note: conversion to enumeration type 'E'
operator E() const { return foo; }
^
6 : note: conversion to enumeration type 'E'
operator E() { return foo; }
^

哪一个是正确的?它是一个铿锵的bug,g ++ bug,libstdc ++ bug,标准缺陷还是其他?我做了些蠢事吗?

在触发此问题的代码中,Cstd::atomic<E>,而std::atomic<T>::operator T在{cv-qualifiers constconst volatile上重载。

两个编译器都接受E e = c;,因此它似乎是switch语句所特有的。

2 个答案:

答案 0 :(得分:18)

这是C ++ 11和C ++ 14之间的区别; clang在C ++ 14模式(-std=c++1y)中正确接受它并在C ++ 11模式(-std=c++11)中拒绝它,而gcc在C ++ 11模式下接受它是不正确的。

switch语句的行为被论文n3323改变了,这是在C ++ 11标准最终确定之后落实的。

[stmt.switch] ,在C ++ 11中:

  

2 - 条件应为整数类型,枚举类型或类型类型,其中存在单个非显式转换函数到整数或枚举类型(12.3)。 [...]

在n3936(根据n3323的措辞):

  

2 - 条件应为整数类型,枚举类型或类类型。如果是类类型,则条件从上下文隐式转换(第4条)为整数或枚举类型。

上下文隐式转换是隐式转换的变体(即声明T t = e需要格式良好);为了使上下文隐式转换格式良好,允许类类型E具有多个转换函数,但在上下文中有效的所有函数必须具有相同的返回类型modulo cv 和引用限定: [conv]

  

5 - [...] E搜索返回类型为 cv T的转换函数或   引用 cv T,以便上下文允许T。应该只有一个T

switch语句中,上下文隐式转换为整数或枚举类型,因此C必须至少有一个非explicit转换函数 cv 整数或枚举类型或对 cv 整数或枚举类型的引用,以及所有其转换函数 cv 整数或枚举类型或对 cv 整数或枚举类型的引用必须具有相同的基础类型。

一个非常好的解决方法(如n3323中所述)是使用一元加号将switch语句的参数强制转换为算术类型:

  switch (+c) {
    // ...

答案 1 :(得分:5)

我相信clang在这里是正确的,具体取决于使用的标准版本。我经常在修复引用之后使用N3485作为C ++ 11,但可以认为我在Classes with both template and non-template conversion operators in the condition of switch statement中注意到的更改是一个附加内容,因此实际上是C ++ 1y的一部分。

因此,对于上下文隐式转换的争用是clang对于draft C++11 standard是正确的。由于部分6.4.2 切换声明表示(强调我的前进):

  

条件应为整数类型,枚举类型或a   一个非显式转换函数的类类型   存在整数或枚举类型(12.3)。[...]

在C ++ 1y中,这应该是可以接受的代码,并且在clang中以C ++ 1y模式运行它似乎确认情况确实如此( see it live )。

我们可以从draft C++1y standard部分6.4.2 切换声明中看到,这涉及上下文隐式转换。段落 2 说:

  

条件应为整数类型,枚举类型或类   类型。如果是类类型,则条件是上下文隐式   转换(第4条)为整数或枚举类型。

我们可以看到我们需要使用的部分是4 标准转化,段落 5 涵盖了这些情况,它说:

  

某些语言结构需要转换为具有一个语言的值   适合于构造的一组指定类型。一个   据说在这样的上下文中出现的类型E的表达式e   从上下文隐式转换到指定的类型T并且是   当且仅当e可以隐式转换为T类时,格式良好   确定如下:搜索E以获得转换函数   其返回类型为cv T或对cv T的引用,以允许T   根据上下文。应该只有一个这样的T.