转载:C++11尝鲜:std::move和std::forward源码分析

std::move和std::forward是C++0x中新增的标准库函数,分别用于实现移动语义和完美转发。
下面让我们分析一下这两个函数在gcc4.6中的具体实现。
预备知识
引用折叠规则:
X& + & => X&
X&& + & => X&
X& + && => X&
X&& + && => X&&
函数模板参数推导规则(右值引用参数部分):
当函数模板的模板参数为T而函数形参为T&&(右值引用)时适用本规则。
若实参为左值 U& ,则模板参数 T 应推导为引用类型 U& 。
(根据引用折叠规则, U& + && => U&, 而T&& ≡ U&,故T ≡ U& )
若实参为右值 U&& ,则模板参数 T 应推导为非引用类型 U 。
(根据引用折叠规则, U或U&& + && => U&&, 而T&& ≡ U&&,故T ≡ U或U&&,这里强制规定T ≡ U )
std::remove_reference为C++0x标准库中的元函数,其功能为去除类型中的引用。
std::remove_reference

[cpp] view plaincopy
template<typename _Tp>  
  inline typename std::remove_reference<_Tp>::type&&  
  move(_Tp&& __t)  
  { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }  
[cpp] view plaincopy
#include<iostream> 
using namespace std;  

struct X {};  

int main()  
{  
    X a;  
    X&& b = move(a);  
    X&& c = move(X());  
}  

代码说明
测试代码第9行用X类型的左值 a 来测试move函数,根据标准X类型的右值引用 b 只能绑定X类型的右值,所以 move(a) 的返回值必然是X类型的右值。
测试代码第10行用X类型的右值 X() 来测试move函数,根据标准X类型的右值引用 c 只能绑定X类型的右值,所以 move(X()) 的返回值必然是X类型的右值。
首先我们来分析 move(a) 这种用左值参数来调用move函数的情况。
模拟单步调用来到源码第3行,_Tp&& ≡ X&, __t ≡ a 。
根据函数模板参数推导规则,_Tp&& ≡ X& 可推出 _Tp ≡ X& 。
typename std::remove_reference<_Tp>::type ≡ X 。
typename std::remove_reference<_Tp>::type&& ≡ X&& 。
再次单步调用进入move函数实体所在的源码第4行。
static_cast

[cpp] view plaincopy
/// forward (as per N3143) 
template<typename _Tp>  
  inline _Tp&&  
  forward(typename std::remove_reference<_Tp>::type& __t)   
  { return static_cast<_Tp&&>(__t); }  

template<typename _Tp>  
  inline _Tp&&  
  forward(typename std::remove_reference<_Tp>::type&& __t)   
  {  
    static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"  
    " substituting _Tp is an lvalue reference type");  
    return static_cast<_Tp&&>(__t);  
  }  
[cpp] view plaincopy
#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&&) 

代码说明
测试代码第13行用X类型的左值 a 来测试forward函数,程序输出表明 outer(a) 调用的是 inner(const X&) 版本,从而证明函数模板outer调用forward函数在将参数左值 a 转发给了inner函数时,成功地保留了参数 a 的左值属性。
测试代码第14行用X类型的右值 X() 来测试forward函数,程序输出表明 outer(X()) 调用的是 inner(X&&) 版本,从而证明函数模板outer调用forward函数在将参数右值 X() 转发给了inner函数时,成功地保留了参数 X() 的右值属性。
首先我们来分析 outer(a) 这种调用forward函数转发左值参数的情况。
模拟单步调用来到测试代码第8行,T&& ≡ X&, t ≡ a 。
根据函数模板参数推导规则,T&& ≡ X& 可推出 T ≡ X& 。
forward(t) ≡ forward

你可能感兴趣的:(转载:C++11尝鲜:std::move和std::forward源码分析)