我直接来自以下代码: http://www.justsoftwaresolutions.co.uk/cplusplus/rvalue_references_and_perfect_forwarding.html
在g ++ 4.8.1编译为:g ++ -std = c ++ 11 testforward.cpp -o testforward.exe
#include <cstdlib>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
class X
{
std::vector<double> data;
public:
X():
data(100000) // lots of data
{}
X(X const& other): // copy constructor
data(other.data) // duplicate all that data
{}
X(X&& other): // move constructor
data(std::move(other.data)) // move the data: no copies
{}
X& operator=(X const& other) // copy-assignment
{
data=other.data; // copy all the data
return *this;
}
X& operator=(X && other) // move-assignment
{
data=std::move(other.data); // move the data: no copies
return *this;
}
};
void g(X&& t)
{
std::cout << "t in g is rvalue" << std::endl ;
}
void g(X& t)
{
std::cout << "t in g is lvalue" << std::endl ;
}
template<typename T>
void f(T&&t)
{
g(std::forward<T>(t)) ;
}
void h(X &&t)
{
g(t) ;
}
int main()
{
X x;
f(x); // 1
f(X()); // 2
//h(x); //compile error
h(X()); // 3
}
根据作者描述如下:
当您将右值引用与函数模板组合时,您会得到一个有趣的交互:如果函数参数的类型是对模板类型参数的右值引用,那么如果传递左值,则将类型参数推导为左值引用,而另一种简单的类型......
此测试的结果输出为:
t in g is lvalue
t in g is rvalue
t in g is lvalue
f(x)得到“t in g is lvalue”就像预期的那样!!
f(X())得到“t in g is rvalue”,是的,这就是std :: forward用于
h(X())得到“t in g is lvalue”,这是我的问题,因为你可以看到函数h 不是模板函数,因为作者描述“当你将rvalue引用与函数模板结合起来时,你会得到一个有趣的交互”并非如此,仍然 这个函数输出“t in g is lvalue”,意味着这个有趣的交互不仅发生在模板函数中,也发生在正常函数中!
如果我将代码更改为:
void h(X &&t)
{
g(std::forward<X>(t)) ;
}
我会得到“是在r值”!!!
Accorind测试,我可以说作者描述“当你将rvalue引用与函数模板结合起来时,你会得到一个有趣的交互”实际上不仅仅是模板函数,它也适用于正常函数,或者我的英文不好,所以我不能理解这个描述吧?!
编辑:
void h(X &&t)
{
g(t) ;
}
void h(X &t)
{
g(t) ;
}
h(x); //get "t in g is lvalue"
h(X()); //get "t in g is lvalue"
=====================================================
void h(X &&t)
{
g(std::forward<X>(t)) ;
}
void h(X &t)
{
g(std::forward<X>(t)) ;
}
h(x); //get "t in g is rvalue"
h(X()); //get "t in g is rvalue"
看起来只在模板函数中,我将获得std :: forward !!!
的cprrect用法答案 0 :(得分:3)
在h(X &&)
中,t
的类型是对X
的r值引用,但命名变量始终被视为l值。因此,即使t
是X &&
,t
也无法直接绑定到X &&
参数,只能绑定X &
个参数。这是为了安全,因为命名变量可以(并且经常会)一次又一次地使用。您不希望第一次使用变量来窃取它,即使它最初绑定到r值。后续使用会看到窃取的值,这很容易导致代码中的逻辑破坏。
如果你知道一个变量是一个r值(或更多的点,如果你知道你已经完成它,无论它是一个l值还是一个r值),那么传递它的方式是r值是使用move()
。当您不知道是否应该窃取原始值时,forward<T>()
的目的是用于通用代码。如果您在模板中使用move()
,则可能会意外地窃取l值。因此,如果forward<T>()
是l值类型,则会使用T
来解析为无害传递,如果move()
是T
,则基本上等同于h
非参考或r值参考。
请注意,在修改中,您h(X &t)
的第二次重载(即forward<>
)错误地使用了t
。在这种情况下,X &
的类型为forward<X&>(t)
,因此您应该使用t
。如果你这样做,你会发现h
作为l值传递。但是,在move()
的两个重载中,您可以看到在第一个中有一个r值引用,在第二个中你有一个l值引用。 (不涉及模板推理,所以你知道类型。)因此,你也可以直接在你的第一次重载中使用forward<T>()
,而不是在你的第二次重载中使用任何东西。 {{1}}的目的是从模板推导中获取信息,以确定它是否被绑定(并推断为)l值或r值。