什么是完美转发?
在理解什么是完美转发之前,需要知道什么是万能引用?
在模板推导过程中,使用T&& a,这时候,并不是类型T的右值引用,而是万能引用,如果a是左值,这时候,就是一个左值引用,如果a是右值,这时候就是一个右值引用,具体原理是发生引用折叠。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| template <typename T> void Add(T&& a, T&& b) { cout << a << endl; cout << b << endl; }
int main() { Add(4, 5); // a,b的类型会被推导成int&& int a = 0; int b = 0; Add(a, b); // a,b的类型会被推导成int& return 0; }
|
根据参数的具体类型,来实例化模板,准确的生成左值引用和右值引用的实例,这就是万能引用
万能引用遇到的问题?
上面的例子中,Add函数参数虽然是类型是右值引用,但是值确实左值,导致函数内继续使用调用其他函数时,参数类型由右值变成左值,也就是无法将右值引用这个类型继续转发.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| template <typename T> void AddImp(T&& a, T&& b) { cout << a << endl; cout << b << endl; }
template <typename T> void Add(T&& a, T&& b) { AddImp(a, b); }
int main() { Add(4, 5); int a = 0; int b = 0; Add(a, b); return 0; }
|
解决方案: std::forward
1 2 3 4 5
| template <typename T> void Add(T&& a, T&& b) { AddImp(std::forward<T>(a), std::forward<T>(b)); }
|
std::forward的具体实现
1 2 3 4 5
| template <class _Tp> _Tp&& forward(typename remove_reference<_Tp>::type& __t) { return static_cast<_Tp&&>(__t); }
|
具体分析一下,也是通过引用折叠来实现
- 如果_Tp的类型是int&, 通过引用折叠 int& && 折叠后是左值引用int&
- 如果_Tp的类型是int&&, 通过引用折叠 int&& && 折叠后是int&&