xsk*_*xzr 7 c++ constructor rvalue-reference move-semantics perfect-forwarding
我们std::pair<T1, T2>
以此为例.它有以下两个构造函数:
constexpr pair( const T1& x, const T2& y ); // #1
template< class U1, class U2 > constexpr pair( U1&& x, U2&& y ); // #2
Run Code Online (Sandbox Code Playgroud)
似乎#2可以处理#1可以处理的所有情况(没有更差的性能),除了参数是list-initializer的情况.例如,
std::pair<int, int> p({0}, {0}); // ill-formed without #1
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:
如果#1仅供列表初始化参数,因为x
并y
最终结合到从列表初始化初始化临时对象,为什么不使用constexpr pair( T1&& x, T2&& y );
呢?
否则,#1的实际意图是什么?
如果您要存储的对象是临时对象但不可移动怎么办?
#include <type_traits>
#include <utility>
#include <iostream>
class test
{
public:
test() { std::cout << "ctor" << std::endl; }
test(const test&) { std::cout << "copy ctor" << std::endl; }
test(test&&) = delete; // { std::cout << "move ctor" << std::endl; }
~test() { std::cout << "dtor" << std::endl; }
private:
int dummy;
};
template <class T1, class T2>
class my_pair
{
public:
my_pair() {}
// Uncomment me plz !
//my_pair(const T1& x, const T2& y) : first(x), second(y) {}
template <class U1, class U2, class = typename std::enable_if<std::is_convertible<U1, T1>::value && std::is_convertible<U2, T2>::value>::type>
my_pair(U1&& x, U2&& y) : first(std::forward<U1>(x)), second(std::forward<U2>(y)) {}
public:
T1 first;
T2 second;
};
int main()
{
my_pair<int, test> tmp(5, test());
}
Run Code Online (Sandbox Code Playgroud)
上面的代码无法编译,因为所谓的“完美”转发构造函数将my_pair
临时test
对象作为右值引用转发,而右值引用又尝试调用显式删除的移动构造函数test
。
my_pair
如果我们从's 不太“完美”的构造函数中删除注释,则重载解析会首选它,并且基本上会强制复制临时test
对象,从而使其工作。