转发引用的绑定优先级
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.6 — S1
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&"
}
有人可以帮我理解为什么下面的代码输出 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 itA
) 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 toA
” is used in place ofA
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 sequenceS2
if
...
/3.2.6 —
S1
andS2
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 byS2
refers is more cv-qualified than the type to which the reference initialized byS1
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&"
}