这是一个小例子,展示了一个不明确的时刻
struct CL
{
CL(){}
CL(int){}
explicit CL(const CL&){}
};
int main() {
CL cl1;
CL cl2=5; //(1)
CL cl3=(CL)5; //(2)
return 0;
}
CL类具有来自int的转换构造函数和标记为显式的复制构造函数。在(1)情况5(int)中隐式转换为CL,然后cl2被直接初始化。在(2)中,cl3是复制初始化的。在这两种情况下都必须涉及显式复制构造函数。但是不同的编译器给出了不同的结果:
铿锵声和VS:第一种情况是正确的,但第二种情况是错误的 gcc:两种情况都是错误的我认为clang和VS是正确的,因为根据标准“explicit”关键字阻止在复制初始化中使用构造函数,但不能在直接初始化中使用gcc是错误的,因为在(1)情况下应用了直接初始化。
谁的编译器是对的?
答案 0 :(得分:2)
§12.3.1[class.conv.ctor] / p2:
显式构造函数构造对象就像非显式构造函数一样,但只在 直接初始化语法(8.5)或显式使用强制转换(5.2.9,5.4)。
示例1:
CL cl2 = 5;
§8.5[dcl.init] / p17:
使用初始化表达式作为其调用选择的函数 参数;如果函数是构造函数,则调用初始化cv-unqualified的临时函数 目标类型的版本。临时是一个prvalue。通话结果(即 临时用于构造函数的情况)然后用于直接初始化,根据上面的规则, 作为复制初始化目标的对象。
在直接初始化中,可以考虑explicit
构造函数,因此不会出现错误。 GCC中继已编译此示例successfully。这是bug 54521。
示例2:
CL cl3 = (CL)5;
在这种情况下,该强制转换语法执行static_cast
:
§5.2.9[expr.static.cast] / p4:
表达式
e
可以使用T
形式的static_cast
显式转换为static_cast<T>(e)
类型 如果声明T t(e);
格式正确,对于一些发明的临时变量t
(8.5)。这样的效果 显式转换与执行声明和初始化相同,然后使用临时转换 变量的结果是变量。
rhs的类型为CL
,而(copy-)初始化需要非explicit
构造函数,因此会出现错误。