C++右值引用浅析(二)
来实现move语义之外,还就是为了解决完美转发的问题。我们有的时候会写工厂函数,比如如下代码:
?
template?
shared_ptr factory(Arg arg)
{?
? return shared_ptr(new T(arg));
}
这个实现非常简单,就是把参数arg传给类T进行构造。但是这里引入了额外的通过值的函数调用,不使用于那些以引用为参数的构造函数。
?
那么为了解决这个问题,就有人想到用引用,比如:
?
template?
shared_ptr factory(Arg& arg)
{?
? return shared_ptr(new T(arg));
}
但是这里又有问题,不能接收右值作为参数。
?
factory(hoo()); // error if hoo returns by value
factory(41); // error
对应的解决办法是继续引入const引用。如果有多个参数的情况下,这个函数的参数列表就变的比较恶心了。同时还有个问题就是不能实现move语义。
?
而右值引用可以解决这个问题,可以不用通过重载函数来实现真正的完美转发。但是它需要配合两个右值引用的规则:
?
引用叠加规则
A& & => A&
A& && => A&
A&& & => A&
A&& && => A&&
模板参数推导规则
template
void foo(T&&);
当函数foo的实参是一个A类型的左值时,T的类型是A&。再根据引用叠加规则判断,最后参数的实际类型是A&。
当foo的实参是一个A类型的右值时,T的类型是A。根据引用叠加规则可以判断,最后的类型是A&&。
?
?
?
有了上面这些规则,我们可以用右值引用来解决前面的完美转发问题。下面是解决的办法:
?
template?
shared_ptr factory(Arg&& arg)
{?
? return shared_ptr(new T(std::forward(arg)));
}
而std::forward的实现如下:
?
template
S&& forward(typename remove_reference::type& a) noexcept
{
? return static_cast(a);
}