2

有人可以帮我理解为什么以下代码输出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 );
}
4

1 回答 1

3

[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&"
}
于 2017-10-29T10:26:45.967 回答