1

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

转发引用只是右值引用(应用了引用折叠规则)吗?

如果它是一个右值引用,那么为什么该函数:

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

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

4

2 回答 2

1

BeforeT被替换,T &&是一个右值引用(显然)。

AfterT被替换(并且在引用折叠之后),T &&要么保持右值引用(如果T不是引用),要么成为左值引用(如果T是左值引用)。

于 2019-07-01T21:42:30.653 回答
1

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

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

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

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

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

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

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

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

于 2019-07-01T21:43:41.983 回答