一 例子
先看一段代码,然后分析。
#include <iostream>
void out(int& t)
{
cout << "out T&" << endl;
}
void out(int&& t)
{
cout << "out T&&" << endl;
}
template<typename T>
void forward(T&& t)
{
out(t);
out(std::forward<T>(t));
out(std::move(t));
}
cout << "forward---------------------------" << endl;
cout << "lvalue: " << endl;
int x = 2;
forward(x);
cout << endl;
cout << endl;
cout << "lvalue refer: " << endl;
int& y = x;
forward(y);
cout << endl;
cout << endl;
cout << "rvalue: " << endl;
forward(1);
cout << endl;
cout << endl;
cout << "rvalue refer: " << endl;
forward(std::move(x));
cout << endl;
cout << endl;
cout << "call out: " << endl;
int n = 1;
int& rn = n;
out(1);
out(n);
out(rn);
结果如下:
forward---------------------------
lvalue:
out T&
out T&
out T&&
lvalue refer:
out T&
out T&
out T&&
rvalue:
out T&
out T&&
out T&&
rvalue refer:
out T&
out T&&
out T&&
call out:
out T&&
out T&
out T&
二 分析
首先介绍两个概念,右值转换和引用折叠原则。
(1) 模板函数参数T&&
若传递的是基本类型为A的左值,则T的类型为A&。
若传递的是基本类型为A的右值,则T的类型为A&&。
(2) 引用折叠原则
A& & 折叠成 A&
A& && 折叠成 A&
A&& & 折叠成 A&
A&& && 折叠成 A&&
(3) 分析
x和y为左值(y类型为左值引用,本身为左值),所以T为int&,则 t 为int& &&, 根据引用折叠,为int&
1和std::move(x)(std::move(x)返回类型为右值引用,本身为右值)为右值,所以T为int&&,则 t 为int&& &&, 根据引用折叠,为int&&
(4) std::forward
两个规则:
<1> Forwards lvalues as either lvalues or as rvalues, depending on T。
When t is a forwarding reference (a function argument that is an rvalue reference to a cv-unqualified function template parameter), this overload forwards the argument to another function with the value category it had when passed to the calling function.
<2> Forwards rvalues as rvalues and prohibits forwarding of rvalues as lvalues。
印证了前三项第二个输出。前三项第三个输出印证std::move的返回类型为右值引用。
前三项第一个和第二个输出印证了通过std::forward可以实现完美转发(参数传递保留左右值属性,且为引用,避免中间的消耗)。
三 注意
模板参数类型推导保留cv限定符(cv-qualifier,const和volatile限定符的统称)。
四 参考