std::move(value)是独立于值的右值引用,一个右值引用参数作为函数的形参,在函数内部再转发该参数的时候已经变成了一个左值,并不是它原来的类型了。
template<typename T>
void forwardValue(T& val)
{
processValue(value); ///右值参数会变成左值
}
template<typename T>
void forwardValue(constT& val)
{
processValue(value); ///参数都变成常量左值引用了
}
上面的参数都没有按照原本的类型进行转发。
因此,我们需要一种方法能按照参数原来的类型转发到另一个函数,这种转发被称为完美转发。所谓完美转发,是指在函数模板中,完全依照模板的参数的类型(即保持参数的左值,右值特征),将参数传递给函数模板中调用的另外一个函数。C++11中提供了这样的一个函数std::forward,它是为转发而生,不管参数是T&&这种未定的引用还是明确的左值引用或者右值引用,它会按照参数本来的类型转发。
#include <iostream>
using namespace std;
void PrintT(int& t)
{
cout << "lvalue" << endl;
}
template<typename T>
void PrintT(T&& t)
{
cout << "rvalue" << endl;
}
template<typename T>
void TestForward(T&& v)
{
PrintT(v);
PrintT(std::forward<T>(v));
PrintT(std::move(v));
}
int main()
{
TestForward(1);
cout << endl;
int x = 1;
TestForward(1);
cout << endl;
TestForward(std::forward<int>(x));
return 0;
}
测试结果如下所示:
我们来分析下测试结果:
TestForward(1):由于1是右值,所以未定的引用类型T&&v被一个右值初始化后变成了一个右值引用,但是在TestForward函数体内部,调用PrintT(v)时,v又变成了一个左值(因为在这里它已经变成了一个具名的变量,所以它是一个左值),因此,第一个PrintT被调用,打印出了"lvalue"。调用PrintT(std::forward<T>(v))时,由于std::forward会按照参数原来的类型转发,因此,它还是一个右值(这里已经发生了类型推导,所以这里的T&&并不是一个未定的引用类型),会调用void PrintT(T&& t)函数。调用PrintT(std::move(v))是将v变成一个右值(v本身也是一个右值),因此,它将输出rvalue。