我一直在看斯科特·迈耶斯的谈论通用参考来自 C++ and Beyond 2012 会议,到目前为止一切都有意义。然而,在50分钟左右,一位观众问了一个我也想知道的问题。迈耶斯说他并不关心答案,因为这不符合惯用语,而且会让他的头脑变得愚蠢,但我仍然感兴趣。
给出的代码如下:
// Typical function bodies with overloading:
void doWork(const Widget& param) // copy
{
// ops and exprs using param
}
void doWork(Widget&& param) // move
{
// ops and exprs using std::move(param)
}
// Typical function implementations with universal reference:
template <typename T>
void doWork(T&& param) // forward => copy and move
{
// ops and exprs using std::forward<T>(param)
}
要点是,当我们获取右值引用时,我们知道我们有一个右值,所以我们应该std::move
它是为了保留它是右值的事实。当我们采用通用参考(T&&
, where T
是推导类型),我们想要std::forward
保留它可能是左值或右值的事实。
所以问题是:自从std::forward
保留传递给函数的值是左值还是右值,并且std::move
只是将其参数转换为右值,我们可以使用std::forward
到处?会std::forward
表现得像std::move
在我们使用的所有情况下std::move
,或者是否存在一些被迈耶斯的概括所遗漏的重要行为差异?
我并不是建议任何人都应该这样做,因为正如迈耶斯正确所说,它完全不惯用,但以下也是有效的用法std::move
:
void doWork(Widget&& param) // move
{
// ops and exprs using std::forward<Widget>(param)
}
两者非常不同并且补充 tools.
也许下面的例子能更好地说明这一点:
#include <utility>
#include <memory>
#include <vector>
#include "foo.hpp"
std::vector<std::unique_ptr<Foo>> v;
template <typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); // #1
}
int main()
{
{
std::unique_ptr<Foo> p(new Foo('a', true, Bar(1,2,3)));
v.push_back(std::move(p)); // #2
}
{
v.push_back(make_unique<Foo>('b', false, Bar(5,6,7))); // #3
}
{
Bar b(4,5,6);
char c = 'x';
v.push_back(make_unique<Foo>(c, b.ready(), b)); // #4
}
}
在情况 #2 中,我们有一个现有的具体对象p
,我们想无条件地摆脱它。仅有的std::move
说得通。这里没有什么可以“转发”的。我们有一个命名变量,我们想从它移走。
另一方面,情况 #1 接受任何类型参数的列表,并且每个参数都需要作为与原始调用中相同的值类别转发。例如,在 #3 中,参数是临时表达式,因此它们将作为右值转发。但是我们也可以在构造函数调用中混合命名对象,如情况 #4 所示,然后我们需要作为左值转发。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)