考虑以下代码:
#include<iostream>
using namespace std;
struct A {
A(const A&){
cout<<"copy constructor"<<endl;
}
A(A&&){
cout<<"move constructor"<<endl;
}
~A(){
cout<<"destructor"<<endl;
}
static std::pair<A,int> f1()
{
int i = 1;
return std::pair<A,int>{i,2};
}
static std::pair<A,int> f2()
{
int i = 1;
return std::pair<A,int>{A(i),2};
}
private:
A(int){
cout<<"constructor"<<endl;
}
};
int main()
{
cout<<"f1: "<<endl;
A::f1();
cout<<"f2: "<<endl;
A::f2();
}
构造函数
A(int)
是私有的,因此 A
中的 pair<A,int>
不能由 int
构建。因此,在f1
中构建了一个临时的。在 f2
中,我显式创建了临时文件,但行为不同,输出为:
f1:
constructor
copy constructor
destructor
destructor
f2:
constructor
move constructor
destructor
destructor
我希望在
A::f1
中也调用移动构造函数,但调用了次优的复制构造函数。为什么会这样?
如果你看对的构造函数
有趣的构造函数是 (2) 和 (3)
// (2)
constexpr pair( const T1& x, const T2& y );
// (3)
template< class U1 = T1, class U2 = T2 >
constexpr pair( U1&& x, U2&& y ); // SFINAE on constructible
注意,没有
pair(T1&&, T2&&)
.
因为
A(int)
是private
,std::is_constructible_v<A, int>
是false
。
所以对于
f1
,只有 (2) 是一个可行的构造函数(因此是副本)。
对于
f2
,(3)是可行的(并且更好的匹配),所以前进(所以移动)完成了。