原样转发的意义
前文我们实现了一个my_move函数,用来模拟stl的move操作,实现去引用的功能。其内部的原理就是通过remove_reference实现去引用操作。
有时我们也需要保留原类型的左值或者右值属性,进行原样转发,此时就要用forward实现转发功能。
我们先定义一个模板函数
1 | template <typename F, typename T1, typename T2> |
flip1内部调用了函数f
我们写一个函数测试
1 |
|
通过打印发现i和j的值没有变化,因为ftemp的v2参数虽然是引用,但是是flip1的形参t1的引用
t1只是形参,修改t1并不能影响外边的实参j。
想要达到修改实参的目的,需要将flip1的参数修改为引用,我们先实现修改后的版本flip2
1 | template <typename F, typename T1, typename T2> |
我们定义了一个flip2函数,t1和t2分别是右值引用类型。接下来用一个测试函数进行测试
1 | int j = 100; |
这次我们发现j被修改了,因为flip2的t1参数类型为T1的右值引用,当把实参j赋值给flip2时,T1变为int&,
t1的类型就是int& &&,通过折叠t1变为int&类型。这样t1就和实参j绑定了,在flip2内部修改t1,就达到了修改j的目的。
但是flip2同样存在一个问题,如果flip2的第一个参数f,如果f是一个接受右值引用参数的函数,会出现编译错误。
为说明这一点,我们实现一个接纳模板参数右值引用类型的函数
1 | void gtemp(int &&i, int &j) |
此时如果我们将gtemp作为参数传递给flip2会报错
1 | int j = 100; |
上面代码仍然会报错,无法将k这个右值引用绑定到m这个左值上。
解决的办法很简单
1 | int i = 100; |
通过int强制类型转换,这是一个表达式得出的就是右值。当然也可以通过如下方式
1 | int i = 100; |
总之就是通过表达式将m转化为右值即可。所以大家要清楚的是及时m是一个int&&类型,但是它本身是一个左值。
综上所述,上面问题的解决的办法就是实现一个flip函数,内部实现对T2,T1类型的原样转发。
1 | template <typename F, typename T1, typename T2> |
通过forward将t2类型转化为和T2类型一样的类型,也就是int的右值类型,接下来的调用就不会出问题了
1 | void use_ftemp() |
模板的可变参数
模板同样支持可变参数
1 | //可变参数的函数模板 |
Args是可变的模板参数包, 然后再用Args定义rest变量,这是一个可变参数列表。
我们的模板函数print内部调用stl的print函数,通过对rest…实现展开操作。
调用过程可按如下的方式
1 | void use_printtemp() |
第一次调用print实际是调用的可变参数的print,之后才调用没有可变参数的print函数。
总结
本文介绍了模板类型的原样转发,以及多模板参数列表的使用。
视频链接https://www.bilibili.com/video/BV1ES4y187Yc/?vd_source=8be9e83424c2ed2c9b2a3ed1d01385e9
源码链接 https://gitee.com/secondtonone1/cpplearn