完美转发的概念和步骤演绎
- 直接调用:比如在main 函数中直接调用funcLast()。
- 转发: 在main 函数中通过funcMiddle()间接调用funcLast。
- funcMiddle相当于一个跳板函数(中间函数)。如果有参数,那么参数也需要通过funcMiddle中转传递给funcLast()。
- 完美转发:实参的属性(const,左值,右值)完全不丢失,原原本本的通过funcMiddle转发给funcLast,这种转发就是完美转发。
void funcLast(int v1, int v2)
{
++v2; //改变v2的值,让其自增1
cout << v1 + v2 << endl;
}
//函数模板(跳板函数):把收到的参数以及这些参数相对应的类型不变的转发给其他函数(完美转发)
template<typename F, typename T1,typename T2>
void funcMiddle_Temp(F f, T1 t1, T2 t2) //f:函数指针类型比如void(*)(int,int),而funcLast是函数类型void(int,int)
{
f(t1, t2);
}
int j = 70;
funcMiddle_Temp( funcLast, 20, j); //输出 91,由于是传值,所以 i 的值不变,仍然是70
- funcLast()函数参数v2改成引用类型,希望可以改变传入的实参的值(输入型参数)
void funcLast(int v1, int &v2)
{
++v2; //改变v2的值,让其自增1
cout << v1 + v2 << endl;
}
template<typename F, typename T1,typename T2>
void funcMiddle_Temp(F f, T1 t1, T2 t2)
{
f(t1, t2);
}
int j = 70;
funcMiddle_Temp(funcLast, 20, j); //91,执行完本函数,j = 70
//当前情况下j被funcMiddle_Temp推断成了int而不是int&
//void funcMiddle_Temp(void(*f)(int,int &),int t1,int t2){...}
- 万能引用:实参的所有信息都会传递到万能引用当中去从而让编译器推导出来函数模板最终的形参类型 (引用折叠)。
void funcLast(int v1, int &v2)
{
++v2; //改变v2的值,让其自增1
cout << v1 + v2 << endl;
}
template<typename F, typename T1,typename T2>
void funcMiddle_Temp(F f, T1&& t1, T2&& t2)
{
f(t1, t2);
}
int j = 70;
funcMiddle_Temp(funcLast, 20, j); //91, T1=int, t1 = int &&, T2 = int & , t2 = int &
//j = 71;
引出完美转发
void funcLast2(int&& v1, int& v2) //v1是右值
{
cout << v1 << endl;
cout << v2 << endl;
}
template<typename F, typename T1,typename T2>
void funcMiddle_Temp(F f, T1&& t1, T2&& t2)
{
f(t1, t2);
}
int j = 70;
funcLast2(20, j); //20,70
funcMiddle_Temp(funcLast2, 20, j);
//20传递到t1(int &&),t1(本身是左值)传递给v1(右值)。
![](https://img-blog.csdnimg.cn/202011132341586.png)
- 完美转发:就是让程序员可以书写接受任意实参的函数模板(funcMiddle_Temp),并将其转发到目标函数(funcLast2),目标函数会接收到与转发函数(funcMiddle_Temp)所接收的完全相同(当然包括类型相同比如保持参数的左值、右值特性)的参数。要实现完美转发,就要用到std::forward了。