1

假设我们有一些代码

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)如果P是一个对cv不合格的模板参数的右值引用(所谓的转发引用),并且对应的函数调用参数是一个左值,则使用对A的类型左值引用代替A进行推导

我想知道的是:“引用折叠”规则是否应用于推导类型 T(而不是 P,参数类型)?

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

4

1 回答 1

3

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

如果表达式最初具有类型“引用”([dcl.ref],[dcl.init.ref]),则在进行任何进一步分析之前T将类型调整为。T

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

因此,在您的示例中,x是 type 的左值int,并且rx是 type 的左值int。在它们的声明和初始化之后,语言在它们之间根本没有区别,除非你再次使用decltype(x)or decltype(rx)

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

于 2019-03-17T22:54:06.933 回答