【问题标题】:Should an explicit copy constructor be ignored?是否应该忽略显式复制构造函数?
【发布时间】:2015-09-06 19:30:23
【问题描述】:

这是一个小例子,展示了一个不清楚的时刻

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) case 5 (int) 中隐式转换为 CL,然后 cl2 被直接初始化。在 (2) 情况下 cl3 被复制初始化。在这两种情况下,都必须涉及显式复制构造函数。但是不同的编译器给出不同的结果:

clang 和 VS:第一种情况是正确的,但第二种情况是错误的
gcc: 两种情况都是错误的

我认为 clang 和 VS 是正确的,因为根据标准“显式”关键字可以防止在复制初始化中使用构造函数,但不能在直接初始化中使用构造函数,并且 gcc 是错误的,因为在 (1) 情况下应用了直接初始化.
谁的编译器是对的?

【问题讨论】:

标签: initialization c++14 explicit


【解决方案1】:

§ 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 可以使用static_cast 形式的static_cast<T>(e) 显式转换为类型T 如果声明 T t(e); 格式正确,则对于某些发明的临时变量 t (8.5)。这样的效果 显式转换与执行声明和初始化然后使用 临时 作为转换结果的变量。

rhs 是CL 类型,并且(复制)初始化需要非explicit 构造函数,因此该错误是预期的。

【讨论】:

    猜你喜欢
    • 2020-10-18
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 2023-04-04
    • 2011-04-28
    相关资源
    最近更新 更多