有人可以帮我理解为什么以下代码输出T&&
而不是const A&
:
class A{};
template< typename T >
void foo( T&& )
{
std::cout << "T&&" << std::endl;
}
void foo( const A& )
{
std::cout << "const A&" << std::endl;
}
int main()
{
A a;
foo( a );
}
有人可以帮我理解为什么以下代码输出T&&
而不是const A&
:
class A{};
template< typename T >
void foo( T&& )
{
std::cout << "T&&" << std::endl;
}
void foo( const A& )
{
std::cout << "const A&" << std::endl;
}
int main()
{
A a;
foo( a );
}
[temp.deduct.call]/1 & 3 [强调我的]:
/1
模板参数推导是通过将
P
包含参与模板参数推导的模板参数的每个函数模板参数类型(调用它)与调用的相应参数类型(调用它)进行比较来完成的,A
如下所述。.../3
...转发引用是对不代表类模板的模板参数的 cv 非限定模板参数的右值引用(在类模板参数推导期间([over.match.class.deduct]))。如果
P
是转发引用并且参数是左值,则使用类型“左值引用A
”代替A
类型推导。[示例:
... template <class T> int f(T&& heisenreference); int i; int n1 = f(i); // calls f<int&>(int&) ...
——结束示例]
应用于您的示例,foo(a)
对于模板参数推导,调用将解析为void foo<A&>(A&)
,这与 cv-unqualified lvalue 完全匹配a
。非模板函数void foo(const A&)
,将通过[over.ics.rank]/3.2.6(感谢@MM 更正消除这两个歧义的排名规则)提供比模板扣除的转换序列更差的转换序列,并且void foo<A&>(A&)
将具有重载决议中的优先级。
/3.2
标准转换序列
S1
是比标准转换序列更好的转换序列,S2
如果
...
/3.2.6 -
S1
并且S2
是引用绑定(8.5.3),并且引用所引用的类型除了顶级cv限定符之外是相同的类型,并且引用所初始化的引用的类型S2
更cv-比由其初始化的引用所引用的类型限定S1
。
如果您修改示例,使非模板重载具有与模板减去一个相同的顶级 cv 限定符(例如,通过const
从非模板函数中删除 cv 限定符),它将导致优先被重载决议选择, .
class A {};
template< typename T >
void foo( T&& )
{
std::cout << "T&&" << std::endl;
}
void foo( A& )
{
std::cout << "A&" << std::endl;
}
int main()
{
A a;
foo( a ); // "A&"
}