Why is template overload a better match than a simple conversion?

百般思念 提交于 2019-12-08 00:35:21

问题


#include <iostream>
using namespace std;

template<typename T>
void func(T t)  { std::cout << "matched template\n"; }

void func(long x) { std::cout << "matched long\n"; }

int main()
{  
    func(0);
}

output:

matched template

In other cases, the non-template function is preferred when overload resolution might be ambiguous, why is this one different?


回答1:


§13.3.3 [over.match.best]/p1-2:

1 Define ICSi(F) as follows:

  • (1.1) [inapplicable bullet omitted]
  • (1.2) let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

  • (1.3) for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

  • [several inapplicable bullets omitted]

  • (1.6) F1 is not a function template specialization and F2 is a function template specialization, or, if not that,
  • [inapplicable bullet omitted]

2 If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution; otherwise the call is ill-formed.

§13.3.3.2 [over.ics.rank], bullet 3.2:

  • (3.2) Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
    • (3.2.1) S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by 13.3.3.1.1, excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence)

Let F1 = func<int>(int), F2 = func(long), there's only one argument, of type int. So ICS1(F1) is the identity conversion; ICS1(F2) is an integer conversion from int to long; therefore ICS1(F1) is a better conversion sequence than ICS1(F2) per [over.ics.rank]/3.2.1 (and so by definition is not worse than ICS1(F2)). Thus per bullet 1.3 in [over.match.best], F1 is better than F2. The template/non-template tiebreaker, in bullet 1.6, simply never comes into play.




回答2:


Implicit conversions may carry an overhead and may be unexpected to the programmer, so it seems logical to me that the standard selects the option which does not involve a conversion.




回答3:


I think (but am not absolutely sure, i.e. don't know the exact quote from the standard, although will try to find) that if the argument does not match exactly the type of the non-template, then the template will kick in. Or, in other words, the number of conversions tends to be minimized. E.g., in

f(long)

vs

template <typename T>
f(T)

f(long) needs a conversion (from 0, e.g.int, to long), whereas no conversion is needed (of course) for the template.

After some digging and help from @T.C., the relevant part of the standard is Sec. 13.3.3, [over.match.best]. This is quite a long technical section, but basically says that the function with the Identity conversion is preferred over non-Identity conversions.



来源:https://stackoverflow.com/questions/29324762/why-is-template-overload-a-better-match-than-a-simple-conversion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!