是否应忽略显式复制构造函数?

时间:2015-09-06 19:30:24

标签: initialization c++14 explicit

这是一个小例子,展示了一个不明确的时刻

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)情况下应用了直接初始化。
谁的编译器是对的?

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构造函数,因此会出现错误。