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,标准缺陷还是其他?我做了些蠢事吗?
在触发此问题的代码中,C
为std::atomic<E>
,而std::atomic<T>::operator T
在{cv-qualifiers const
和const volatile
上重载。
两个编译器都接受E e = c;
,因此它似乎是switch
语句所特有的。
答案 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
搜索返回类型为 cvT
的转换函数或 引用 cvT
,以便上下文允许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.