According to the C++23 standard, what is the output of this program?
#include <iostream>
template <class T> void f(T &i) { std::cout << 1; }
template <> void f(const int &i) { std::cout << 2; }
int main() {
int i = 42;
f(i);
}What exactly will be the deduced parameter type in the primary template? Is that a better or a worse match than the explicit specialization for the call f(i)?
1
There are two alternatives for the call to f here, the primary function template, and the explicit specialization. So we need overload resolution to figure out which one to call.
Overload resolution when function templates are involved works like this (summarized from §[temp.over]¶1):
We start with type deduction:
T is deduced from the call f(i) as int, and the parameter type is int &.const int&.Overload resolution now has to find a conversion sequence from the argument i to each of the parameter types int & and const int &, and if one conversion sequence is better, that's the one that's chosen. If neither is better than the other, the call is ill-formed.
Both int & and const int & can bind directly to i, so no conversion is needed in either case. So far there's a tie, but §[over.ics.rank]¶3.2.6 has the answer:
Standard conversion sequence
S1is a better conversion sequence than standard conversion sequenceS2if— (...)
—
S1andS2include reference bindings (§[dcl.init.ref]), 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 byS2refers is more cv-qualified than the type to which the reference initialized byS1refers.
The types to which the references refer are int for S1 and const int for S2. Those are indeed the same types except for top-level cv-qualifiers, and const int is indeed more cv-qualified than int, so S1 is a better conversion sequence and the primary function template is the best viable function.
The primary function template is thus called, and 1 is printed.