#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?
§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 functionF
. 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 functionF2
if for all argumentsi
,ICSi(F1)
is not a worse conversion sequence thanICSi(F2)
, and then
(1.3) for some argument
j
,ICSj(F1)
is a better conversion sequence thanICSj(F2)
, or, if not that,[several inapplicable bullets omitted]
- (1.6)
F1
is not a function template specialization andF2
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 sequenceS2
if
- (3.2.1)
S1
is a proper subsequence ofS2
(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.
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.
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