C++ 完美转发之 std::forward
2025-03-31
为什么需要完美转发?
在 C++11 之前,泛型函数在传递参数时无法保持参数的原始类型(左值或右值),导致额外的拷贝或移动操作。完美转发是一种高效传递参数的技术,能够保持参数的原始特性(左值传递左值,右值传递右值),避免额外的开销。
代码例子
注意,万能引用 = 右值引用 + 模板。如果没有模板,就是普通的右值引用。
未使用完美转发
下面的代码中,我们没有使用完美转发,而是直接将参数传递到了
process
函数中。
1 |
|
调用的结果,均调用了左值引用:
1 | Lvalue reference: 10 |
我们明明传的是右值,结果两个函数间接调用 process
时最终都调用了左值的版本。这是因为
forwardExample(T&& arg)
到这一层时,arg
在 process
看来已经是一个有地址的变量,将其看成了左值。
使用完美转发
下面的代码中,我们使用了完美转发。
1 | template<typename T> |
调用的结果完美符合了我们的期望,左值调用左值重载,右值调用右值重载:
1 | Lvalue reference: 10 |
完美转发的实现原理
std::forward<T>(arg)
通过引用折叠和类型推导来保证传递原始的参数特性。
T 传递的类型 |
T&& 推导后 |
std::forward<T>(arg)
结果 |
---|---|---|
int |
int&& |
右值 int&& |
int& |
int& && →
int& |
左值 int& |
int&& |
int&& && →
int&& |
右值 int&& |
实际上就是左值引用会污染,万能引用沾染上一个左值引用就变成左值引用了。
完美转发的应用场景
- 传递构造函数参数:有可能很多类的构造函数有左值右值重载,
std::forward
可以确保arg
以最佳方式传递给构造函数。 - 传递函数参数:文中的例子。