提问者:小点点

转发引用是否仍然是rvalue引用?


我仍然被那些为了支持移动和转发而发明的规则弄糊涂了。有一件事我还不太确定:

转发引用是否只是rvalue引用(应用了引用折叠规则)?

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

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

不仅接受rvalues,还接受lvalues?


共2个答案

匿名用户

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

当这种情况作为模板参数推演的结果发生时,作为一个方便的速记,整个构造被称为“转发引用”。(这种情况需要引用折叠,但模板参数推演并不是引用折叠发生的唯一时间。)

现在来看看标准的措辞。首先,我们有[dcl.ref](例如p2、p6):

使用&声明的引用类型称为lvalue引用,使用&声明的引用类型称为rvalue引用。[...]

如果typedef-name(9.1.3,13.1)或decltype-specifier(9.1.7.2)表示对t类型的引用tr类型的tr类型,则尝试创建类型“lvalue reference to cvtr”将创建类型“lvalue reference tot”,而尝试创建类型“rvalue reference to cvtr”将创建类型“tr”将创建类型“tr”。[注:此规则称为引用折叠。-结尾注]

最后,模板参数推演的情况在[temp.defint.call]P3中处理:

转发引用是对cv-unqualified模板参数[...]的rvalue引用

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

匿名用户

t被替换之前,t&&是一个rvalue引用(显然)。

T被替换之后(以及在引用折叠之后),T&或者保持rvalue引用(如果T不是引用),或者成为lvalue引用(如果T是lvalue引用)。