C++ C2440:';初始化';:无法从';A<;双倍>';至';A<;双倍>';

C++ C2440:';初始化';:无法从';A<;双倍>';至';A<;双倍>';,c++,visual-c++,variable-assignment,C++,Visual C++,Variable Assignment,此代码在Visual Studio 2017中引发编译错误: #包括 #包括 使用std::cin; 使用std::cout; 样板 甲级 { 公众: A(ta); ~A(){} #如果0 A(常数A&); #否则 A(A&); #恩迪夫 T; }; 样板 A::A(ta):T(A){} 样板 #如果0 A::A(常数A&A) #否则 A::A(A&A) #恩迪夫 { t=a.t; std::cout在这种情况下,特别缺少MSVC错误消息;如果在上面运行GCC,则会出现以下错误: main.cp

此代码在Visual Studio 2017中引发编译错误:

#包括
#包括
使用std::cin;
使用std::cout;
样板
甲级
{
公众:
A(ta);
~A(){}
#如果0
A(常数A&);
#否则
A(A&);
#恩迪夫
T;
};
样板
A::A(ta):T(A){}
样板
#如果0
A::A(常数A&A)
#否则
A::A(A&A)
#恩迪夫
{
t=a.t;

std::cout在这种情况下,特别缺少MSVC错误消息;如果在上面运行GCC,则会出现以下错误:

main.cpp: In function ‘int main()’:
main.cpp:42:20: error: cannot bind non-const lvalue reference of type ‘A<double>&’ to an rvalue of type ‘A<double>’
   42 |     A<double> a3 = A<double>(a2);  //gives C2440 when copy constructor argument is not const.
      |                    ^~~~~~~~~~~~~
main.cpp:28:15: note:   initializing argument 1 of ‘A<T>::A(A<T>&) [with T = double]’
   28 | A<T>::A(A<T>& a)
      |         ~~~~~~^
make: *** [<builtin>: main] Error 1
仍然返回相同的错误:

main.cpp: In function ‘int main()’:
main.cpp:2:13: error: cannot bind non-const lvalue reference of type ‘double&’ to an rvalue of type ‘double’
    2 |   double &a = 2.71;
      |             ^~~~
make: *** [<builtin>: main] Error 1
仅调用复制构造函数一次,使用
左值(
a2
),而第二个:

A<double> a3 = A<double>(a2);
a3=A(a2);

调用复制构造函数两次,第一次使用如上所述的
lvalue
a2
),第二次使用
rvalue
(第一次构造函数调用的结果)。但是,优化将删除其中一个调用,乍一看可能会让人困惑,因为这两个复制构造函数调用中的哪一个可能会导致问题。

因为不允许修改临时的,这就是非常量引用参数的意思,“我要修改参数。”为了改进这个问题,请发布可以不经修改而编译的版本以给出错误(而不是发布正确的版本并描述给出错误的修改)。也没有必要包含非错误的版本。注意-由于C++17,
a3=a(a2);
完全等同于
a3{a2};
,但您使用的编译器版本可能不支持C++17或未设置为该模式。当我使用C++17编译时,我得到相同的结果:
a3{a2}
工作,并且
a3=A(a2)
在没有const参数的情况下选择复制构造函数时不会编译。啊,在@M.M.我可以确认,使用clang和gcc,当设置
-std=c++17
时,它编译时不会出错。
a3=A(a2)
如何调用复制构造函数两次?为什么不只调用一次?第一次调用是在
A(a2)
,第二个用于在分配给
a3
时代替自定义赋值运算符。请注意,如前所述,通常会对其中一个运算符进行优化;更重要的是,C++17几乎保证了复制省略,作为更改的一部分。如果
a(a2)
将左值(a2)分配给左值引用(
a&a)
,然后赋值将左值引用(
A&A)
分配给左值(a3),那么您声称我将右值分配给左值引用的空间在哪里呢?首先,在C++17之前,
A(a2)的结果
是一个右值。其次,编译器将查找or实现,如果找不到,则返回到已实现的复制构造函数。因此,最终结果是尝试将右值(
a(a2)
)绑定到非常量左值引用(
a&a
)。
A<double> a3{a2};
A<double> a3 = A<double>(a2);