首页 > 解决方案 > 非常量复制构造函数可以用 C++17 编译

问题描述

我想知道为什么下面的代码不能用 C++14 编译,但用 C++17 编译得很好。自 C++17 以来有什么可以改变的想法吗?事情当然是关于 A 类的非常量复制构造函数。我使用的是 VS 2019。这段代码是否有效?

class A {
public:
    A() { }
    A(A& a) { }
};

A fun() {
    A a;
    return a;
}

int main()
{
    A a = fun();
}

来自编译器的消息:

  1. A 类没有合适的复制构造函数
  2. 初始化无法从 A 转换为 A
  3. 由于不明确的复制构造函数或没有可用的复制构造函数,无法复制构造类 A

标签: c++c++17c++14language-lawyercopy-constructor

解决方案


fun()是一个 prvalue 类型A,所以A a = fun();意味着它a是函数调用的结果对象,没有中间临时对象。

这方面的文字在 C++17 [basic.lval]/2 中:

prvalue的结果对象是prvalue初始化的对象;

对等来说也是一样的A a = A(A(A(A(A(fun())))));——所有纯右值都a作为它们的结果对象。

return 语句的行为在 [stmt.return]/2 中:

return语句通过操作数的复制初始化 (11.6) 来初始化(显式或隐式)函数调用的泛左值结果或纯右值结果对象。

a结果对象可以通过(的局部变量)的复制初始化成功初始化,fun因为这是一个非常量左值,因此采用非常量左值引用的复制构造函数确实绑定到它。


在 C++17 之前fun()的返回值是一个临时对象,然后 main 是从临时对象a复制/移动构造的,省略是可选的(但需要存在有效的构造函数)。


推荐阅读