文章目录
- 万能引用/通用引用(universal reference)
- 引用折叠
- 完美转发(std::forward)
万能引用/通用引用(universal reference)
C++11增加了右值的概念,在模板中,可以用&&来表示右值引用,也可以用&&来表示万能引用。
1.如果重载了模板函数,一个参数是左值引用,一个参数是右值引用,那传入左值或者右值时会自动推导调用的函数模板。
2.如果只有一个模板函数,参数的写法是右值引用,此时传入左值或者右值都会调用这个模板函数。
因为这里的&&代表的是万能引用。
引用折叠
万能引用的实现原理是引用折叠,即模板函数的参数是 T&&,T的类型可以是int&或者int&&,T展开就是int& &&,或者int&& &&,此时发生引用折叠,左值引用还是折叠成左值,右值引用还是右值引用。
完美转发(std::forward)
不论函数的形参是左值引用还是右值引用,在传入函数后,在函数中再传入一个函数时,参数会丢失左值右值信息,在新的函数中会被视为左值。
为了保护参数的左值或者右值属性,就有了完美转发(std::forward<>())。
它的实现原理大概是:
Tempalte <typename T>
std::forward(typename std::remove_reference<T>::type& arg)
{static_cast<T&&>(t);
}
#include <iostream>using namespace std;#define _STD_FORWARD_USED_template <typename T>
void Print(T& t)
{cout << "Print param is lr." << endl;
}template <typename T>
void Print(T&& t)
{cout << "Print param is rr." << endl;
}template <typename T>
void Test_Func(T&& t)
{
//当模板的参数出现&&时,他可能是右值引用,也可能是万能引用。cout << "Test_Func" << endl;
#if defined(_STD_FORWARD_USED_)Print(std::forward<T>(t)); //当使用std::forward<>()时,形参t保留了左值或者右值的属性。//因为保留了参数的初始属性,这就是[完美转发]。
#elsePrint(t); //当不使用std::forward<>()时,形参t被转换成了左值。
#endif
}int GetIntNum()
{return 1;
}
int main()
{int i = 9;int &li = i;int&& ri = GetIntNum();Test_Func(i);Test_Func(li);//这里有参数折叠,我们传入的是ing&,即T是int&,//此时实参列表式 int & &&,参数折叠为左值引用:int&。Test_Func(GetIntNum());//这里有参数折叠,我们传入的是右值,即T是右值引用int&&,//此时实参列表式 int && &&,参数折叠为右值引用:int&&。
}
输出结果:
->Not defined _STD_FORWARD_USED_* Test_Func* Print param is lr.* Test_Func* Print param is lr.* Test_Func* Print param is lr. ->defined _STD_FORWARD_USED_* Test_Func* Print param is lr.* Test_Func* Print param is lr.* Test_Func* Print param is rr.-->在defined _STD_FORWARD_USED_的基础上,注释void Print(T& t),仅保留void Print(T&& t)也是可以的。-->因为仅用&&函数时,&&就从右值引用,变成了万能引用。