要求的参考折叠规则的简明解释:(1) & - > A& ,(2)A& &&& - > A& ,(3)A& & - > A& ,(4)A& &&& - > A&& [英] Concise explanation of reference collapsing rules requested: (1) A& & -> A& , (2) A& && -> A& , (3) A&& & -> A& , and (4) A&& && -> A&&

查看:178
本文介绍了要求的参考折叠规则的简明解释:(1) & - > A& ,(2)A& &&& - > A& ,(3)A& & - > A& ,(4)A& &&& - > A&&的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下链接提供了4种参考折叠形式(如果我确定这些是唯一的4种形式): http://thbecker.net/articles/rvalue_references/section_08.html



从链接:



  1. A& &成为A&

  2. A& &&&成为A&&&&& &成为A&&&&& &&&成为A&&&&


虽然我可以做一个有根据的猜测,



一个相关的问题,如果我可能:这些引用崩溃规则在C ++ 11中使用 std :: move() std :: forward() ,等等,在典型的现实世界的用例? (注意:我特别询问是否在C ++ 11中使用参考 - 折叠规则,而不是C ++ 03或更早版本。)



这个相关的问题,因为我知道这样的C ++ 11实用程序 std :: remove_reference ,但我不知道如果参考相关的实用程序如 std :: remove_reference 经常在C ++ 11中使用以避免需要参考 - 折叠规则,或者它们是否与参考折叠规则。

解决方案

参考折叠规则( A& ;> A& ,这是C ++ 98/03)存在的原因之一是:允许完美的转发工作。



完美转发意味着有效地转发参数,如同用户直接调用该函数(减去elision,它被转发中断)。用户可以传递三种值:lvalues,xvalues和prvalues,接收位置有三种方式可以取值:by value,by(可能const)lvalue引用和by(可能const)rvalue

 模板< class T> 
void Fwd(T& v){Call(std :: forward< T>(v);}



按值



如果调用按值取其参数,如果输入值是一个左值,那么它必须复制左值,如果输入值是一个右值(它们共同是xvalue和prvalues),那么它必须发生在该参数中,



如果你使用左值调用 Fwd ,C ++的类型推导规则意味着 T 将被推导为 Type& ,其中类型显然,如果lvalue是 const ,它将被推导为 const Type& 。参考折叠规则意味着类型&&&& 变为类型& for v ,一个左值引用,这正是我们需要调用 Call 。用一个左值引用调用它将强制一个副本,正如我们已经调用它



如果您使用xvalue调用 Fwd (ie:certain Type&& ; 表达式),则 T 将被推导为 Type&& 。参考折叠规则规定类型&& &&&&< / code>会再次成为键入&&&& ,这是我们需要调用 Call 。如果你调用 Fwd()方法,调用它的非常量右值引用将强制一个移动/副本,就像我们直接调用它。



<
与prvalue(即:类型临时表达式),则将推导出 T as 键入。参考折叠规则给我们 Type&&& ,它再次引发一个移动/副本,就像我们直接调用它(减去elision)。



由lvalue引用



如果调用 ,那么它应该只在用户使用左值参数时可调用。如果是const-lvalue引用,那么它可以被任何东西调用(lvalue,xvalue,prvalue)。



如果调用 Fwd 与类型为 v ,我们再次获得 Type& 这将绑定到非常量值引用。如果我们使用const lvalue调用它,我们得到 const Type& ,它只绑定到 Call



如果用xvalue调用 Fwd ,我们再次获得 Type& ;& 作为 v 的类型。这将允许您调用一个接受非常量值的函数,因为xvalue不能绑定到非常量的值。它可以绑定到一个常量值引用,因此如果调用使用一个 const& ,我们可以调用<$ c $



如果你使用prvalue调用 Fwd 我们再次得到 Type&&& ,所以一切都像以前一样工作。



由rvalue引用

h3>

如果调用通过rvalue引用获取它的值,那么它只能在用户使用xvalue或lvalue参数时调用。



如果您使用左值调用 Fwd ,则会得到 Type& 。这不会绑定到右值引用参数,因此会导致编译错误。 A const Type& 也不会绑定到右值引用参数,因此它仍然失败。如果我们直接用一个左值调用 Call 就会发生这种情况。



如果调用 Fwd 与xvalue,我们得到 Type&&& >

使用prvalue也是如此。



std :: forward



std :: forward本身以类似的方式使用引用折叠规则,以便将传入的右值引用传递为xvalues(函数返回值 Type&& 是xvalue)和传入的左值引用作为l值(返回 Type& )。


The following link provides the 4 forms of reference collapsing (if I'm correct that these are the only 4 forms): http://thbecker.net/articles/rvalue_references/section_08.html.

From the link:

  1. A& & becomes A&
  2. A& && becomes A&
  3. A&& & becomes A&
  4. A&& && becomes A&&

Although I can make an educated guess, I would like a concise explanation for the rationale behind each of these reference-collapsing rules.

A related question, if I might: Are these reference-collapsing rules utilized in C++11 internally by such STL utilities such as std::move(), std::forward(), and the like, in typical real-world use cases? (Note: I'm specifically asking whether the reference-collapsing rules are utilized in C++11, as opposed to C++03 or earlier.)

I ask this related question because I am aware of such C++11 utilities as std::remove_reference, but I do not know if the reference-related utilities such as std::remove_reference are routinely used in C++11 to avoid need for the reference-collapsing rules, or whether they are used in conjunction with the reference-collapsing rules.

解决方案

The reference collapsing rules (save for A& & -> A&, which is C++98/03) exist for one reason: to allow perfect forwarding to work.

"Perfect" forwarding means to effectively forward parameters as if the user had called the function directly (minus elision, which is broken by forwarding). There are three kinds of values the user could pass: lvalues, xvalues, and prvalues, and there are three ways that the receiving location can take a value: by value, by (possibly const) lvalue reference, and by (possibly const) rvalue reference.

Consider this function:

template<class T>
void Fwd(T &&v) { Call(std::forward<T>(v); }

By value

If Call takes its parameter by value, then a copy/move must happen into that parameter. Which one depends on what the incoming value is. If the incoming value is an lvalue, then it must copy the lvalue. If the incoming value is an rvalue (which collectively are xvalues and prvalues), then it must move from it.

If you call Fwd with an lvalue, C++'s type-deduction rules mean that T will be deduced as Type&, where Type is the type of the lvalue. Obviously if the lvalue is const, it will be deduced as const Type&. The reference collapsing rules mean that Type & && becomes Type & for v, an lvalue reference. Which is exactly what we need to call Call. Calling it with an lvalue reference will force a copy, exactly as if we had called it directly.

If you call Fwd with an xvalue (ie: certain Type&& expressions), then T will be deduced as Type&&. The reference collapsing rules state that Type && && becomes Type&& again, which is what we need to call Call. Calling it with a non-const rvalue reference will force a move/copy, exactly as if we had called it directly.

If you call Fwd with a prvalue (ie: a Type temporary expression), then T will be deduced as Type. The reference collapsing rules give us Type &&, which again provokes a move/copy, exactly as if we had called it directly (minus elision).

By lvalue reference

If Call takes its value by lvalue reference, then it should only be callable when the user uses lvalue parameters. If it's a const-lvalue reference, then it can be callable by anything (lvalue, xvalue, prvalue).

If you call Fwd with an lvalue, we again get Type& as the type of v. This will bind to a non-const lvalue reference. If we call it with a const lvalue, we get const Type&, which will only bind to a const lvalue reference argument in Call.

If you call Fwd with an xvalue, we again get Type&& as the type of v. This will not allow you to call a function that takes a non-const lvalue, as an xvalue cannot bind to a non-const lvalue reference. It can bind to a const lvalue reference, so if Call used a const&, we could call Fwd with an xvalue.

If you call Fwd with a prvalue, we again get Type&&, so everything works as before. You cannot pass a temporary to a function that takes a non-const lvalue, so our forwarding function will likewise choke in the attempt to do so.

By rvalue reference

If Call takes its value by rvalue reference, then it should only be callable when the user uses xvalue or lvalue parameters.

If you call Fwd with an lvalue, we get Type&. This will not bind to an rvalue reference parameter, so a compile error results. A const Type& also won't bind to an rvalue reference parameter, so it still fails. And this is exactly what would happen if we called Call directly with an lvalue.

If you call Fwd with an xvalue, we get Type&&, which works (cv-qualification still matters of course).

The same goes for using a prvalue.

std::forward

std::forward itself uses reference collapsing rules in a similar way, so as to pass incoming rvalue references as xvalues (function return values that are Type&& are xvalues) and incoming lvalue references as lvalues (returning Type&).

这篇关于要求的参考折叠规则的简明解释:(1) &amp; - &gt; A&amp; ,(2)A&amp; &amp;&amp;&amp; - &gt; A&amp; ,(3)A&amp; &amp; - &gt; A&amp; ,(4)A&amp; &amp;&amp;&amp; - &gt; A&amp;&amp;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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