完美转发
完美转发,旨在解决在函数模板中准确无误地转发参数的值,还能保证被转发参数的左、右值属性不变。
在早期的 C++ 中,当你通过一个函数向另一个函数传递参数时,参数的左值/右值属性会丢失,这意味着即使有可用的移动构造函数,编译器也只能调用拷贝构造函数。
为了解决这个问题,C++11 引入了新的工具和概念:右值引用和移动语义,所以,能否实现完美转发,决定了该参数在传递过程使用的是拷贝语义还是移动语义。
1)通用引用/转发引用: 在函数模板中,如果一个参数的类型为 T&&
,并且这个类型 T
是通过模板推断得来的,那么这个参数就不是一个普通的右值引用,而是所谓的“通用引用”或“转发引用”。这种引用可以绑定到一个左值上(此时 T
被推断为 Type&
),也可以绑定到一个右值上(此时 T
被推断为 Type
)。
示例:
template<typename T>
void wrapper(T&& arg) {
// some operations
}
2)forward: forward<T>
是一个用于实现完美转发的模板函数,它可以保持一个值的左值/右值属性。如果传递给 forward
的参数是一个右值引用,它就会返回一个类似的右值引用,如果传递的是左值引用,它就返回一个左值引用。
示例:
template<typename T>
void wrapper(T&& arg) {
// 使用 forward 转发 arg
// 如果 arg 是右值,它被转发为右值;如果是左值,它被转发为左值
some_function(forward<T>(arg));
}
在这个例子中,forward<T>(arg)
保证 arg
作为与原始参数同样类型的引用(左值或右值)被转发给 some_function
函数。
下面是一个完整实例:
#include <iostream>
#include <utility> // for forward
using namespace std;
// 普通函数,用以检验参数的左/右值性
void foo(int& x) { cout << "foo(int&): " << x << endl; }
void foo(int&& x) { cout << "foo(int&&): " << x << endl; }
// 完美转发模板函数
template <typename T>
void bar(T&& x) {
foo(forward<T>(x));
}
int main() {
int a = 5;
// 使用左值调用 bar,bar 内部会调用 foo(int&)
bar(a);
// 使用右值调用 bar,bar 内部会调用 foo(int&&)
bar(10);
return 0;
}