【问题标题】:Is a forwarding reference still an rvalue reference or not?转发引用是否仍然是右值引用?
【发布时间】:2021-06-14 20:33:22
【问题描述】:

我仍然对为支持移动和转发而发明的规则感到困惑。我仍然不确定的一件事是:

是转发引用只是右值引用(与 引用折叠规则)?

如果是右值引用,那么函数为什么会这样:

template<typename T>
void func(T&&);

不仅接受右值,还接受左值?

【问题讨论】:

标签: c++ c++11 rvalue-reference lvalue forwarding-reference


【解决方案1】:

我不确定这个答案是否会让你满意,但我可以指出标准的相关部分。简而言之,引用 T&amp;&amp; 在“语法上”始终是右值引用,但有时它最终声明的类型是左值引用类型。

当由于模板参数推导而发生这种情况时,整个构造被称为“转发引用”,作为一种方便的简写。 (这种情况需要引用折叠,但模板参数推导并不是唯一发生引用折叠的情况。)

现在,进入标准措辞。首先我们有[dcl.ref](例如p2p6):

使用&amp; 声明的引用类型称为左值引用,使用&amp;&amp; 声明的引用类型称为右值引用。 [...]

如果 typedef-name (9.1.3, 13.1) 或 decltype-specifier (9.1.7.2) 表示类型 TR 是对一个类型T,尝试创建类型“对cvTR的左值引用”创建类型“对T的左值引用”,而 尝试创建类型“对 cv TR 的右值引用”会创建类型 TR。 [注意:此规则称为引用折叠。 — 尾注]

最后在[temp.deduct.call]p3处理模板参数推导的情况:

转发引用是对 cv 非限定模板参数的右值引用 [...]

换句话说,转发引用一个右值引用,但它也接受左值。 (请注意,标准对“转发引用”的定义实际上并不需要推导模板参数,尽管这是您通常希望触发引用折叠行为的主要方式。)

【讨论】:

  • 我会在“转发引用”的定义后面加上一句,这是剩下的关键部分,在某种意义上与引用折叠相反,以使转发引用推导真正起作用。虽然它确实假定知道 PA 在该部分的上下文中是什么。
  • @aschepler:也许,虽然问题不在于转发是如何工作的,而是关于用于各种相关结构的术语,我相信上面已经涵盖了这些术语。
  • @Kerrek SB 非常感谢!但是......“转发引用是一个右值引用,但它也是一个接受左值的引用。”听起来很奇怪……怎么可能?
【解决方案2】:

T 被替换之前,T &amp;&amp; 是一个右值引用(显然)。

T 被替换后(引用被折叠后),T &amp;&amp; 要么保持右值引用(如果 T 不是引用),要么变为左值引用(如果 T 是左值引用)。

【讨论】:

  • ITYM "在T 被替换之前,T&amp;&amp; 是一个右值引用。" T 本身通常是非引用类型,例如如果表达式是非字符串非函数文字或调用返回非引用类型的函数。
  • @aschepler 确实,“它”是指T &amp;&amp;。为清晰起见进行了编辑。
  • “如果 T 不是参考”?不,“如果 T 不是左值引用”!
  • @Deduplicator T 如果T &amp;&amp; 是转发引用,则永远不会被推断为右值引用。
  • @HolyBlackCat See it for yourself。引用折叠将&amp;&amp; &amp;&amp;&amp;&amp; 折叠为&amp;&amp;,从无到无,以及其他所有内容到&amp;
猜你喜欢
  • 2011-07-04
  • 2011-04-12
  • 2018-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
  • 1970-01-01
相关资源
最近更新 更多