当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?

Why does the class reference constructor overload get called from an rvalue when there's an rvalue constructor available?

本文关键字:构造函数 值调用 引用 重载 为什么      更新时间:2023-10-16

此代码

#include <iostream>
struct A
{
A(int i) {std::cout << "int receivedn";}
A(A& a) {std::cout << "ref receivedn";}
};
int main()
{
int j = 5;
A a = j;
}

意外引发以下编译器错误:

error: invalid initialization of non-const reference of type 'A&' from an rvalue of type 'A'
note:   initializing argument 1 of 'A::A(A&)'
note:   after user-defined conversion: A::A(int)

当我删除第二个构造函数重载A(A& a)时,一切都按预期工作。我想编译器错误地调用了第二个构造函数而不是第一个构造函数。

为什么会这样?

如何让同时具有引用构造函数和右值构造函数的类协调工作?

我使用 GNU GCC。

注意:我还注意到一些奇怪的事情:显然,如果我将行A a = j;替换为A a(j);,一切都按预期工作。然而,这并不令人满意,因为如果我尝试从函数参数初始化对象(例如:使用f(j)调用void f(A a)(,它仍然不起作用。

A a = j;执行复制初始化。

直到C++17,

如果T是类类型,并且other类型的 cv 非限定版本不是T或派生自T,或者如果T是非类类型,但other的类型是类类型,则用户定义的转换序列可以从other类型转换为T(或派生自T的类型,如果T是类类型和转换功能可用(,并通过过载分辨率选择最佳功能。转换的结果(如果使用转换构造函数,则为prvalue temporary (until C++17)prvalue expression (since C++17)(随后用于直接初始化对象。The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

A有一个复制构造器,将左值引用用于非常量,它不能绑定到从int临时转换的 .即使从临时A构造也可能优化复制构造函数必须可用。

使复制构造函数对const采用左值引用(或添加移动构造函数(将解决此问题。

由于 C++17 由于强制复制省略,代码可以正常工作。

这些对象直接构造到存储中,否则它们将被复制/移动到存储中。复制/移动构造函数不需要存在或可访问:

另一方面,A a(j);执行直接初始化,a直接从j初始化,复制构造函数不参与。