There is some very basic example of C++ function template overloading resolution below (minimized from actual code)
struct S {
S() {}
S(int) {}
};
template <typename T = S>
void foo(T x) { std::cout << "S" << std::endl; }
template <>
void foo<S>(S x) { std::cout << "S spc" << std::endl; }
int main() {
foo({});
foo(0);
}
Here we have two cases. In first case compiler shall default-initialize something (like S) in second case convert int to something (like S)
I believe in both cases specialization shall win overloading because specialization perfectly matches and is really more specialized then primary template by partial ordering [temp.deduct.partial]
But both clang 11 and gcc 10.2 in this example agrees that in second case primary template wins. Is this bug in both compilers or (probably) I don't understand something about C++ standard?
There's only a single candidate that participates in overload resolution:
template <typename T=S> void foo(T);
The selection of function template specializations happens afterwards. In this case, we have:
foo({})
can't deduce T
(because {}
has no type), so instead we fall back to using the default argument for T
, which is S
. That gives us a viable candidate to call - foo<S>
.
Once we decide to call foo<S>
, we then consider specializations. There is one, so it is chosen. This prints "S spc"
foo(0)
can deduce T
, T
is int
. That gives us a viable candidate to call - foo<int>
. There is no specialization for this, this [misleadingly] prints "S"
(even though there is no S
involved here).
Default template arguments only come into play when the actual template parameter can either not be deduced or is not explicitly provided.
If you wanted even foo(0)
to call foo<S>
, you need to prevent deduction from succeeding in picking int
. But at that point, why even have a template, just have a function that takes an S
.