转载

翻译「C++ Rvalue References Explained」C++右值引用详解 Part7:Perfect Forwarding(完美转发):...

本文为第七部分,目录请参阅概述部分: http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.html 。

Perfect Forwarding(完美转发):问题

Move语义背后右值引用用来解决的另一个问题是完美转发问题。考虑下面这样简单的工厂函数:

template<typename T, typename Arg>  shared_ptr<T> factory(Arg arg) {    return shared_ptr<T>(new T(arg)); }

显然,这里的目的是想要将arg参数通过工厂函数传递到T的构造函数中去。理想情况,就arg而言,一切应该表现得如果没有工厂函数一样,构造器直接被客户的代码调用:也就是完美转发。上面的代码很不幸在这种状况下失败了:它引入了一个额外的传值调用,当构造器使用引用类型作为参数时,那么这样就是很糟糕的了。

一个更为普遍的解决方案,例如被boost::bind所采用的,就是让外层的函数的参数使用引用类型:

template<typename T, typename Arg>  shared_ptr<T> factory(
Arg&
 arg) {    return shared_ptr<T>(new T(arg)); }

这样更好,但也并非完美。问题就是现在的工厂函数并不能被右值所调用:

factory<X>(hoo()); // error:如果hoo通过值返回 factory<X>(41); // error

这可以通过提供一个const reference的参数重载来解决:

template<typename T, typename Arg>  shared_ptr<T> factory(
Arg const &
 arg) {    return shared_ptr<T>(new T(arg)); }

这个方法有两个问题。首先,如果factor不仅仅只有一个,而是有很多个参数的话,你就需要提供所有对non-const和const reference参数的组合重载。因此,这种解决方案当面临到函数有很多参数的时候可伸缩性是很差的。

第二个,这种方法并不是完美的是因为它会阻挡move语义:在factory函数体中的T构造器重的参数是一个左值。因此,move语义永远不会发生即使没有外在的包装函数。

事实证明右值引用可以用来解决这类问题。它使得可以不用通过任何的重载就可以实现真正的完美转发。为了理解它是如果运作的,我们需要先看一下右值引用的两个规则。

正文到此结束
Loading...