C++通用引用和LRef参数的类型推导

C++ Universal Reference and type deduction of LRef parameter

假设我们有一些代码

template <typename T>
void Foo(T&& param);

int x = 5;
// deduced Foo<int&>(int&).
// Argument type A = int. T = int&.
Foo(x);     

int& rx = x;
// deduced Foo<int&>(int& &&) -> Foo<int&>(int&).
// But... argument type A = int&, an lvalue reference to int.
// Is T = int& or under the hood it is T = int& &?
Foo(rx);

根据https://en.cppreference.com/w/cpp/language/template_argument_deduction

4) If P is an rvalue reference to a cv-unqualified template parameter (so-called forwarding reference), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction

我想知道的是:'reference collapsing' 规则是否应用于推导类型 T(而不是 P,参数类型)?

所以我们真的有 'Foo(rx)' T = int& &,它折叠成 T = int&?

请注意,实际上,出于所有技术目的,表达式的类型永远不会被视为引用类型。 [expr.type]/1:

If an expression initially has the type "reference to T" ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis.

一个值得注意的例外是当 decltype() 应用于未加括号的名称或 class 成员访问表达式时。尽管语法将名称视为表达式,但语义结果涉及名称的声明类型 而不是 表达式的类型和值类别。

因此在您的示例中,x 是类型 int 的左值,而 rx 是类型 int 的左值。在它们的声明和初始化之后,语言对它们没有任何区别,除非你再次使用 decltype(x)decltype(rx).

这意味着 Foo(rx) 的模板类型推导与 Foo(x) 的工作方式完全相同:类型 Aint,而不是 int&,参数是左值。根据您引用的规则,T 被推断为 int&,并且当将 T=int& 代入函数类型时,引用折叠规则表明 T&&int&.