转发引用的绑定优先级

Binding priority of forwarding reference

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

Template argument deduction is done by comparing each function template parameter type (call it P) that contains template-parameters that participate in template argument deduction with the type of the corresponding argument of the call (call it A) as described below. ...

/3

... A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template (during class template argument deduction ([over.match.class.deduct])). If P is a forwarding reference and the argument is an lvalue, the type “lvalue reference to A” is used in place of A for type deduction.

[ Example:

...
template <class T> int f(T&& heisenreference);
int i;
int n1 = f(i);                  // calls f<int&>(int&)
...

— end example]

应用于您的示例,foo(a) 调用将针对模板参数推导解析为 void foo<A&>(A&),它与 cv-unqualified 左值 a 完全匹配。非模板函数 void foo(const A&),将由 [over.ics.rank]/3.2.6(感谢 @M.M 纠正消除这两个歧义的排名规则),提供比模板扣除的转换序列更差的转换序列,并且void foo<A&>(A&) 将优先处理重载决议。

/3.2

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

  • ...

  • /3.2.6S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.

如果您修改示例,使非模板重载具有与模板相同的顶级 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&"
}