std :: forward和std :: move的用法 [英] Usage of std::forward vs std::move

查看:271
本文介绍了std :: forward和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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆