std::forward完美转发

发布时间 2023-03-31 19:50:59作者: _Explosion!

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