通用引用和转发引用有什么区别?

71
这个函数的参数将会绑定到一个右值引用:
void f(int && i);

然而,该函数的参数将绑定到rvalue或lvalue引用之一:
template <typename T>  
void f(T && t);

我经常听到这被称为通用引用。
我也听说它被称为转发引用。
它们是指同一件事吗?
只有当函数体调用 std::forward 时,它才是一个转发引用吗?


2
请参阅https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers以获取一些背景资料。 - Sam Varshavchik
3
@SamVarshavchik 你真的读了问题或那篇博客吗? - Barry
2个回答

83

它们的意思是一样的吗?

通用引用 是Scott Meyers创造的术语,用来描述获取一个对于cv-unqualified模板参数的右值引用,然后可以将其推导为值或左值引用的概念。

当时的C++标准没有专门的术语来描述这个概念,在C++11中疏忽了这一点,这使得教学变得困难。这个疏漏在N4164中得到了纠正,它在[temp.deduct]中添加了以下定义:

一个转发引用是对于cv-unqualified模板参数的右值引用。如果P是一个转发引用并且参数是一个左值,则在类型推导中使用“左值引用到A”的类型代替A。

因此,这两个术语意思相同,当前C++标准术语是转发引用。该论文本身阐述了为什么“转发引用”比“通用引用”更好的术语。
“只有在函数体调用std :: forward时才是转发引用吗?”
不是的,你对转发引用的操作与名称无关。转发引用的概念仅涉及在以下代码中如何推断类型T:
template <class T> void foo(T&& ); // <== 

它不需要随后转发。

3
很好的回答!你有没有(非平凡的)例子,在这个转发引用上不会调用 std::forward?你也可以提到局部变量的 auto&& 情况。 - vsoftco
3
@vsoftco template <class F> void foo(F&& arg) { use(arg); use_again(arg); consume(std::forward<F>(arg)); } - Barry
提醒:如果类型既不是const也不是volatile,则为“cv-unqualified”类型。请参见https://dev59.com/12Up5IYBdhLWcg3wPFv_。 - luca
@vsoftco 是的,例如一个简单的基于范围的for循环。我不太确定为什么他们觉得有必要使用术语“转发引用”,而不是大家已经在使用的成熟术语“通用引用”。 - 303
@303 我的回答链接到介绍转发引用的论文,它为“为什么他们觉得有必要”引入它提供了一个答案。你可以同意或反对那里提出的论点,但你不必对为什么感到困惑。 - Barry
显示剩余4条评论

19

不幸的是,它很令人困惑,但它们只是同一事物的两个名称。
通用引用最早由梅耶斯(Meyers)在很久以前提出(请参见这里作为示例)。
转发引用直接从标准文献中选用。 就是这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接