std::forward被称为完美转发,它的作用是保持原来的值属性不变。
啥意思呢?通俗的讲就是,如果原来的值是左值,经std::forward处理后该值还是左值;如果原来的值是右值,经std::forward处理后它还是右值。
简单样例如下:
#include <iostream> template<typename T> void print(T & t){ std::cout << "左值" << std::endl; } template<typename T> void print(T && t){ std::cout << "右值" << std::endl; } template<typename T> void testForward(T && v){ print(v); print(std::forward<T>(v)); print(std::move(v)); } int main(int argc, char * argv[]) { testForward(1); std::cout << "======================" << std::endl; int x = 1; testFoward(x); }
上述代码输出结果为:
左值 右值 右值 ========================= 左值 左值 右值
可以看到,我们在第一个testForward函数中传入了一个立即数1(右值),但是在函数体内,经过函数传参变成了左值(此处理解为,在函数中传入
的右值1通过形参的修饰有了变量名v,在内存中有了位置,从而变成了左值)。而std::forward使其又变回原来的右值。std::move函数强行转移资源所有权,一定是右值。
第二次testForward函数中传入了一个变量(左值),同上所述,第一行为左值,而第二行std::forward仍然保持其原本的左值属性,第三行move为右值。
从而可得出std::forward函数的功能,即完美转发参数,保持其原有的属性。
实际上,真正的完美转发= std::forward + 万能引用 + 引用折叠。三者合一才能实现完美转发的效果。
还是上面的例子,testForward函数是一个模板函数,其中形参T&&为万能引用,根据引用折叠规则,&& & == &,&& && == &&
因此传入立即数1时,函数可实例化为:(此处只针对第二行打印讲)
T = int //T万能引用绑定到右值上时,不会发生引用折叠,所以这里没有引用折叠。直接变成了int
void testForward(int && v){ print(std::forward<int>(v)); }
在std::forward函数的作用下(详细可见std::forward定义↓),其接收左值返回左值,接收右值返回右值
template <typename T> T&& forward(typename std::remove_reference<T>::type& param) { return static_cast<T&&>(param); } template <typename T> T&& forward(typename std::remove_reference<T>::type&& param) { return static_cast<T&&>(param); }
传入的T现在的属性是int,因此std::forward返回类型为int&&。
如果最开始传入的是变量x,则根据万能引用,T的类型为int && &==int &,那么std::forward返回类型便是int&& &==int &。
个人理解,对应个体函数来说,即便传入的参数类型int &&,在万能引用的作用下变成了int,但其此时作为一个内存中存在的变量int其实际是左值。
而std::forward对传入类型为int型的结果可使其返回一个类型为int&&的结果。
参考文章https://zhuanlan.zhihu.com/p/369203981
https://zhuanlan.zhihu.com/p/161039484