C++中的std::forward函数是一个非常有用的工具,主要用于在泛型编程中完美转发(perfect forwarding)参数。在C++中,完美转发是指将函数模板中接收到的参数以原始形式(左值或右值)转发给另一个函数,保持参数的值类别(左值或右值)不变。1
2
3
4
5template<typename T> //C++14;仍然在std命名空间
T&& forward(remove_reference_t<T>& param)
{
return static_cast<T&&>(param);
}
假设有一个函数f:
1 | template<typename T> |
假设传入是左值
传入到f的实参是Widget的左值类型。T被推导为Widget&,然后调用std::forward将实例化为std::forward<Widget&>。Widget&带入到上面的std::forward的实现中:
1 | Widget& && forward(remove_reference_t<Widget&>& param) |
最终forward转化为返回一个左值引用
1 | Widget& forward(Widget& param) |
当左值实参被传入到函数模板f时,std::forward被实例化为接受和返回左值引用。内部的转换不做任何事,因为param的类型已经是Widget&,所以转换没有影响。左值实参传入std::forward会返回左值引用。通过定义,左值引用就是左值,因此将左值传递给std::forward会返回左值,就像期待的那样
假设传入是右值
传递给f的实参是一个Widget的右值。在这个例子中,f的类型参数T的推导类型就是Widget。f内部的std::forward调用因此为std::forward<Widget>,std::forward实现中把T换为Widget得到:
1 | Widget&& forward(remove_reference_t<Widget>& param) |
最终转化为:
1 | Widget&& forward(Widget& param) |
从函数返回的右值引用可以被定义为右值,最终结果是,传递给f的右值参数将作为右值转发给someFunc,正是想要的结果。
从函数返回的右值引用可以被定义为右值的理解:
如果不加forward,传入右值,fParam推导类型是Widget&&,最终直接传入someFunc,它是有名字(fParam)的,所以是一个左值。
1 | template<typename T> |
加了forward后,forward返回一个Widget&&类型,返回是有个匿名变量,它是一个右值
1 | template<typename T> |