c++11 perfect forwarding

完美转发是c++11 引入右值引用之后,在template 中的延伸. 顾名思义,完美转发是将参数不改变属性的条件下,转发给下一个函数. 因为普通函数的参数一旦具名,始终都是lvalue. 如果把rvalue转发到下一个函数上的参数中,还是rvalue.这就是完美转发的目的。

#include<iostream>
using namespace std;
 
struct X {};
void inner(const X&) {cout << "inner(const X&)" << endl;}
void inner(X&&) {cout << "inner(X&&)" << endl;}
template<typename T>
void outer(T&& t) {inner(forward<T>(t));}
 
int main()
{
	X a;
	outer(a);
	outer(X());
	inner(forward<X>(X()));
}
//inner(const X&)
//inner(X&&)
//inner(X&&)

那么如何支持完美转发呢?第一反应就是用通用引用;假设如此实现:

template<class T>
T&& forwarding(T&& t){
  return static_cast<T&&>(param);
}

 传入左值的时候是forward(x), 传入右值是forward(X()),看起来符合要求。但是这里用错了完美转发的具体场景,也就是通常我们用完美转发是什么形式呢?如果不使用完美转发,那么在template function会出现什么情况?

template <typename T>
void relay(T&& t) {
    cout << "in relay" << endl;
    func(t);
}

 relay(temp());传入的是右值,但是转发的时候t被认为左值. 不符合完美转发语义

template<typename T>
void foo(T&& fparam)
{
    std::forward<T>(fparam);
}

  

 以上是完美转发的场景,完美转发配套通用引用,才是它的应用场景, 因为param已经具名,所以是lvalue,刚才的简单实现,显然不符合。

template <typename T>
T&& forward(typename remove_reference<T>::type& param)
{
    return static_cast<T&&>(param);
}

 以上实现,才是完美转发的主要实现,为什么是主要实现,因为它是最多场景的实现。我们分析一下foo(A());T被推导为A,fparam是lvalue,param是A&。因此匹配

但是如果我们翻C++ 完美转发的实现:貌似还有另外一个实现:
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
这里应对什么场景呢?直接调用forward<A>(A())的场景。 注意这里typename remove_reference<T>::type&&不再是通用引用,而是右值引用。之前的左值引用,不能接右值,所以需要重定义一个函数.

以上就实现了完美转发的所有内容.完美转发的根基是引用折叠和通用引用.
   其他:
template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;}; 

  

 

posted @ 2019-02-27 17:19  kkshaq  阅读(194)  评论(0编辑  收藏  举报