为什么需要使用通用引用的参数,在使用之前? [英] Why parameters of universal reference needs to be casted, before used?

查看:223
本文介绍了为什么需要使用通用引用的参数,在使用之前?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于通用参考文献,Scott Meyers(大约40分钟)说,在使用之前,应该将通用引用的对象转换为实数类型。换句话说,每当有一个具有通用引用类型的模板函数时,在使用操作符和表达式之前应使用 std :: forward ,否则对象的副本可能

In the lecture about universal references, Scott Meyers (at approximately 40th minute) said that objects that are universal references should be converted into real type, before used. In other words, whenever there is a template function with universal reference type, std::forward should be used before operators and expressions are used, otherwise a copy of the object might be made.

我对此的理解在以下示例中:

My understanding of this is in the following example :

#include <iostream>

struct A
{
  A() { std::cout<<"constr"<<std::endl; }
  A(const A&) { std::cout<<"copy constr"<<std::endl; }
  A(A&&) { std::cout<<"move constr"<<std::endl; }
  A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
  A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }

  ~A() { std::cout<<"destr"<<std::endl; }

  void bar()
  {
    std::cout<<"bar"<<std::endl;
  }
};

A getA()
{
  A a;
  return a;
}

template< typename T >
void callBar( T && a )
{
  std::forward< T >( a ).bar();
}

int main()
{
  {
    std::cout<<"\n1"<<std::endl;
    A a;
    callBar( a );
  }

  {
    std::cout<<"\n2"<<std::endl;
    callBar( getA() );
  }
}

如预期,输出为:

1
constr
bar
destr

2
constr
move constr
destr
bar
destr

这个问题真的是为什么是需要的?

The question really is why is this needed?

std::forward< T >( a ).bar();

我试过没有std :: forward,它似乎工作正常(输出是相同的) 。

I tried without std::forward, and it seems to work fine (the output is the same).

同样,为什么他建议使用带有右值的函数内部的move? (答案与std :: forward相同)

Similarly, why he recommends to use move inside the function with rvalue? (the answer is the same as for std::forward)

void callBar( A && a )
{
  std::move(a).bar();
}



我理解 std :: move std :: forward 只是转换为适当的类型,但是在上面的例子中这些转型真的需要吗?

I understand that both std::move and std::forward are just casts to appropriate types, but are these casts really needed in the above example?

Bonus:如何修改示例以生成传递给该函数的对象的副本?

Bonus : how can the example be modified to produce the copy of the object that is passed to that function?

推荐答案

演讲中说的是这样:

void doWork( Widget&& param )
{
  ops and exprs using std::move(param)
}




SM:这意味着:如果你看到代码需要一个右值引用,并且你看到该参数的使用,而不被移动包装,这是高度怀疑。

SM: What this means is : if you see code that takes a rvalue reference, and you see use of that parameter without being wrapped by move, it is highly suspect.

经过一番思考,我意识到这是正确的(如预期)。在原始示例中更改 callBar 函数可以证明这一点:

After some thought, I realized that it is correct (as expected). Changing the callBar function in the original example to this demonstrate the point :

void reallyCallBar( A& la )
{
  std::cout<<"lvalue"<<std::endl;
  la.bar();
}

void reallyCallBar( A&& ra )
{
  std::cout<<"rvalue"<<std::endl;
  ra.bar();
}

template< typename T >
void callBar( T && a )
{
  reallyCallBar( std::forward< T >( a ) );
}

如果 std :: forward 未在 callBar 中使用,则将使用 reallyCallBar(A&)。因为 a 在 callBar 中是一个左值引用。 std :: forward 使通用引用为右值引用时为一个右值。

If the std::forward wasn't used in callBar, then the reallyCallBar( A& ) would be used. Because a in callBar is a lvalue reference. std::forward makes it a rvalue, when the universal reference is the rvalue reference.

更进一步:

void reallyCallBar( A& la )
{
  std::cout<<"lvalue"<<std::endl;
  la.bar();
}

void reallyCallBar( A&& ra )
{
  std::cout<<"rvalue"<<std::endl;
  reallyCallBar( ra );
}

template< typename T >
void callBar( T && a )
{
  reallyCallBar( std::forward< T >( a ) );
}

std :: move 不在 reallyCallBar(A&& ra)函数中使用,它不会进入无限循环。

Since std::move is not used in the reallyCallBar( A&& ra ) function, it doesn't enter the endless loop. Instead it calls the version taking lvalue reference.

因此(如演讲中所解释):

Therefore (as explained in the lecture) :


  • std :: forward 必须用于通用引用
  • / code>必须用于右值引用
  • std::forward must be used on universal references
  • std::move must be used on rvalue references

这篇关于为什么需要使用通用引用的参数,在使用之前?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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