C++ std::forward 与 std::move 的使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28828159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Usage of std::forward vs std::move
提问by bweber
I always read that std::forward
is only for use with template parameters. However, I was asking myself why. See the following example:
我总是读到它std::forward
仅用于模板参数。然而,我问自己为什么。请参阅以下示例:
void ImageView::setImage(const Image& image){
_image = image;
}
void ImageView::setImage(Image&& image){
_image = std::move(image);
}
Those are two functions which basically do the same; one takes an l-value reference, the other an r-value reference. Now, I thought since std::forward
is supposed to return an l-value reference if the argument is an l-value reference and an r-value reference if the argument is one, this code could be simplified to something like this:
这是两个基本相同的功能;一个采用左值参考,另一个采用右值参考。现在,我想既然std::forward
应该返回一个左值引用,如果参数是左值引用,如果参数是一个右值引用,那么这段代码可以简化为这样的:
void ImageView::setImage(Image&& image){
_image = std::forward(image);
}
Which is kind of similar to the example cplusplus.com mentions for std::forward
(just without any template parameters). I'd just like to know, if this is correct or not, and if not why.
这有点类似于 cplusplus.com 提到的示例std::forward
(只是没有任何模板参数)。我只想知道,这是否正确,如果不正确,为什么。
I was also asking myself what exactly would be the difference to
我也在问自己到底有什么区别
void ImageView::setImage(Image& image){
_image = std::forward(image);
}
回答by Angew is no longer proud of SO
You cannotuse std::forward
without explicitly specifying its template argument. It is intentionally used in a non-deduced context.
如果不明确指定其模板参数,则不能使用std::forward
。它有意用于非推导的上下文中。
To understand this, you need to really understand how forwarding references (T&&
for a deduced T
) work internally, and not wave them away as "it's magic." So let's look at that.
要理解这一点,您需要真正了解转发引用(T&&
对于推导T
)如何在内部工作,而不是将它们挥之不去,因为“它很神奇”。让我们来看看。
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
Let's say we call foo
like this:
假设我们这样调用foo
:
foo(42);
42
is an rvalue of type int
. T
is deduced to int
. The call to bar
therefore uses int
as the template argument for std::forward
. The return type of std::forward<U>
is U &&
. In this case, that's int &&
, so t
is forwarded as an rvalue.
42
是一个类型的右值int
。T
推导出来int
。bar
因此int
,对的调用用作 的模板参数std::forward
。的返回类型std::forward<U>
是U &&
。在这种情况下,就是int &&
,所以t
作为右值转发。
Now, let's call foo
like this:
现在,让我们这样调用foo
:
int i = 42;
foo(i);
i
is an lvalue of type int
. Because of the special rule for perfect forwarding, when an lvalue of type V
is used to deduce T
in a parameter of type T &&
, V &
is used for deduction. Therefore, in our case, T
is deduced to be int &
.
i
是一个类型的左值int
。由于完美转发的特殊规则,当类型的左值V
用于推导T
类型的参数时T &&
,V &
使用推导。因此,在我们的例子中,T
被推导出为int &
。
Therefore, we specify int &
as the template argument to std::forward
. Its return type will therefore be "int & &&
", which collapses to int &
. That's an lvalue, so i
is forwarded as an lvalue.
因此,我们将 指定int &
为模板参数std::forward
。因此,它的返回类型将是“ int & &&
”,它会折叠为int &
. 这是一个左值,因此i
作为左值转发。
Summary
概括
Why this works with templates is when you do std::forward<T>
, T
is sometimes a reference (when the original is an lvalue) and sometimes not (when the original is an rvalue). std::forward
will therefore cast to an lvalue or rvalue reference as appropriate.
为什么这适用于模板是当你这样做时std::forward<T>
,T
有时是参考(当原始是左值时),有时不是(当原始是右值时)。std::forward
因此将根据需要转换为左值或右值引用。
You cannot make this work in the non-template version precisely because you'll have only one type available. Not to mention the fact that setImage(Image&& image)
would not accept lvalues at all—an lvalue cannot bind to rvalue references.
您无法在非模板版本中准确地进行此操作,因为您将只有一种类型可用。更不用说setImage(Image&& image)
根本不接受左值的事实——左值不能绑定到右值引用。
回答by Ron Tang
I recommend reading "Effective Modern C ++" ,its author is Scott Meyers.
我推荐阅读“Effective Modern C++”,它的作者是Scott Meyers。
Item 23: Understand std :: move and std :: forward.
Item 24: Distinguish universal references for rvalue references.
From a purely technical perspective, the answer is yes: std::forward can do it all.std::move isn't necessary. Of course, neither function is really necessary, because we could write casts everywhere, but I hope we agree that that would be,well, yucky. std::move's attractions are convenience, reduced likelihood of error, and greater clarity.
第 23 条:理解 std::move 和 std::forward。
第 24 条:区分右值引用的通用引用。
从纯粹的技术角度来看,答案是肯定的:std::forward 可以做到这一切。std::move 不是必需的。当然,这两个函数都不是必需的,因为我们可以在任何地方编写强制转换,但我希望我们同意这会很糟糕。std::move 的吸引力在于方便、减少出错的可能性和更清晰。
rvalue-reference:This function accepts rvalues cannot accept lvalues.
rvalue-reference:这个函数接受右值不能接受左值。
void ImageView::setImage(Image&& image){
_image = std::forward(image); //error
_image = std::move(image);//conventional
_image = std::forward<Image>(image);//unconventional
}
Note first that std::move requires only a function argument , while std::forward requires both a function argument and a template type argument.
首先注意 std::move 只需要一个函数参数,而 std::forward 需要一个函数参数和一个模板类型参数。
template <typename T> void ImageView::setImage(T&& image){
_image = std::forward<T>(image);
}
universal references(forwarding references):This function accepts all and does perfect forwarding.
通用引用(转发引用):此函数接受所有并进行完美转发。
回答by Chris Drew
You have to specify the template type in std::forward
.
您必须在std::forward
.
In this context Image&& image
is alwaysan r-value reference and std::forward<Image>
will always move so you might as well use std::move
.
在此上下文Image&& image
中始终是 r 值引用并且std::forward<Image>
将始终移动,因此您不妨使用std::move
.
Your function accepting an r-value reference cannot accept l-values so it is not equivalent to the first two functions.
您接受 r 值引用的函数不能接受左值,因此它不等同于前两个函数。