Search code examples
c++templatesoverload-resolution

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


#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?


Solution

  • §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.