c++c++20function-templates-overloading

C++ function template overload: empty braces vs explicit int


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)

Live example on godbolt

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?


Solution

  • 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:

    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.