问题
The need for this function stems from the fact that all named values (such as function parameters) always evaluate as lvalues (even those declared as rvalue references)
就是说右值引用本身其实是个左值。比如:
#include <stdio.h>
#include <utility>
int gettmp() {
return 2;
}
void test(int &)
{
printf("call &\n");
}
void test(int &&)
{
printf("call &&\n");
}
template<typename T>
void forwardtest(T &&t)
{
// 执行到这里时 t 的类型是个左值
test(t); // 输出 call &
}
int main()
{
int && tmp = gettmp();
tmp = 3; // tmp可以是左值,并对它赋值。
test(tmp); // 输出 call&
test(2); // 2 是个右值,输出call&&
forwardtest(2);//2是个右值,但还是输出call&,因为在forwardtest里面t是个左值
return 0;
int &a = tmp;
}
输出:
call &
call &&
call &
如何让forwardtest中 t 的类型保留它原始的类型呢:如果t是左值就调用test时让t是左值,如果t是右值调用test让t是右值?
std::forward
主要作用就是得到变量原始的类型 ,把forwardtest中调用test(t)改为:test(std::forward(t))就可以了。
template<typename T>
void forwardtest(T &&t)
{
test(std::forward<T>(t));
}
输出:
call &
call &&
call &&
std::forward引用折叠
在forwardtest函数的类型推导过程中会用到引用折叠. 详细的可以查阅更多其它资料:effective modern c++ item 28,会讲std::forward怎么实现的以及引用折叠
T& & -> T&
T& && -> T&
T&& & -> T&
T&& && -> T&&
只有T的类型是T&&时, t的类型才是T&&, 其它的情况t的类型是T&.
下面是std::forward的实现
remove_reference_t不管理T的类型是&类弄还是&&类型,都把&去掉得到T的没有引用的类型,比如:
- remove_reference_t<int&>得到 int
- remove_reference_t<int&&>也会得到 int
template<typename T> // C++14; still in
T&& forward(remove_reference_t<T>& param) // namespace std
{
return static_cast<T&&>(param);
}
比如当传入的参数是int& 得到如下推导,最后forward返回int&:
int& && forward(int & param) // namespace std
{
return static_cast<int& &&>(param);
}
引用折叠后得到:
int& forward(int & param) // namespace std
{
return static_cast<int&>(param);
}
当传入的参数是int&& 得到如下推导,最后forward返回int&&:
int&& && forward(int & param) // namespace std
{
return static_cast<int&& &&>(param);
}
引用折叠后得到:
int&& forward(int & param) // namespace std
{
return static_cast<int&&>(param);
}
参考
what-are-the-main-purposes-of-using-stdforward-and-which-problems-it-solves