std :: forward和std :: move的用法 [英] Usage of std::forward vs std::move
问题描述
我总是看到 std :: forward
只能用于模板参数。然而,我问自己为什么。请参阅以下示例:
void ImageView :: setImage(const Image& image){
_image = image;
}
void ImageView :: setImage(Image&& image){
_image = std :: move(image);
}
这两个函数基本上是一样的;一个采用l值参考,另一个采用r值参考。现在,我认为因为 std :: forward
应该返回一个l值引用如果参数是一个l值引用和r值引用如果参数是一个,这个代码可以简化成这样:
void ImageView :: setImage(Image& image){
_image = std :: forward(image);
}
这是类似于cplusplus.com的例子 std :: forward
(没有任何模板参数)。我想知道,如果这是正确的,如果不是,如果不是为什么。
我也问自己,到底是什么会有区别
void ImageView :: setImage(Image& image){
_image = std :: forward(image);
}
/ em>使用 std :: forward
,而不明确指定其模板参数。
要理解这一点,你需要真正理解转发引用( T&& / code>为一个推导的
T
)在内部工作,而不是浪费他们作为它的魔法。因此,让我们来看看。
模板< class T&
void foo(T& t)
{
bar(std :: forward< T>(t));
}
假设我们调用 foo
像这样:
foo(42)
42
是 int
。 T
被推导为 int
。因此, bar
的调用使用 int
作为 std :: forward
。
std :: forward< U>
的返回类型为 U&&
。在这种情况下,这是 int&&
,因此 t
作为右值转发。
现在,让我们像这样调用 foo
:
code> int i = 42;
foo(i);
i
c $ c> int 。由于完全转发的特殊规则,当 V
类型的左值用于在参数中推导 T
类型 T&&&
, V&
用于扣除。因此,在我们的例子中, T
被推导为 int&
。
因此,我们指定 int&
作为 std :: forward
的模板参数。因此它的返回类型将为 int&&&&
,其折叠为 int&
。这是一个左值,所以 i
被转发为一个左值。
摘要 p>
为什么使用模板是当你执行 std :: forward< T>
, T
有时是引用(当原始值是左值时),有时不是(当原始值是右值时)。 std :: forward
将适当地转换为一个左值或右值引用。
非模板版本,因为你只有一个类型可用。更不用说 setImage(Image&&&&& amp; image)
不会接受所有的lvalue值; lvalue不能绑定到rvalue引用。
I always read that std::forward
is only for use with template parameters. However, I was asking myself why. See the following example:
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:
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.
I was also asking myself what exactly would be the difference to
void ImageView::setImage(Image& image){
_image = std::forward(image);
}
You cannot use std::forward
without explicitly specifying its template argument. It is intentionally used in a non-deduced context.
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.
template <class T>
void foo(T &&t)
{
bar(std::forward<T>(t));
}
Let's say we call foo
like this:
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.
Now, let's call foo
like this:
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 &
.
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.
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.
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.
这篇关于std :: forward和std :: move的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!