How to determine the primary template of a function specialization?
Let's focus on the declaration of the generic templates (1) and (2). These are two distinct templates, e.g. (2) is not a specialization of (1). Ok, now when we write a specialization:
template <>
void foo(int, int) {}
When deducing which template to specialize, the compiler will identify two candidates. Then, it must chose which is the best fit. The process for such a choice is called "partial ordering of function templates". Chosen quote:
When the same function template specialization matches more than one overloaded function template (this often results from template argument deduction), partial ordering of overloaded function templates is performed to select the best match.
Let's call S the set of matching templates. Then, for each pair (f1, f2) in S, the compiler will transform f1 by applying dummy types (resp. values) on its type (resp. non type) parameters. Then it tries to match it against f2. Then it does the same procedure by transforming f2 and trying to match it against f1. At the end, after going through each pair, the compiler can determine which template candidate is the most specialized. If it fails to do so the compilation fails.
In our case we've got two matching templates so we apply the procedure described above:
- Transformed (1) applied to (2): Say foo with T = T1 and U=T2. It tries to match with (2): deduction fails
- Transformed (2) applied to (1): foo(T1, T1), when applied to (1), it resolves as T = T1 and U = T1.
From this procedure, the compiler deduces that (2) is more specialized than (1) and your specialization goes for (2). The same process is applied during overload resolution when the compiler focuses on a particular call.
An example illustrating all this procedure is the following (taken from @Yakk's comment):
template <typename T, typename U>
void f(T, U) { std::cout << "f(1)\n"; } // f(1)
template <typename T>
void f(T, T) { std::cout << "f(2)\n"; } // f(2)
template <>
void f(int, int) { std::cout << "f(3)\n"; } // f(3); specializes f(2), not f(1); why?
// Now the same specialization but without any template overload...
template <typename T, typename U>
void g(T, U) { std::cout << "g(1)\n"; } // g(1)
template <>
void g(int, int) { std::cout << "g(3)\n"; } // g(3); No ambiguity, specializes g(1)
Next, let's perform a few calls:
f(1, 1); // Prints f(3)
f<int>(1, 1); // Prints f(3)
f<int, int>(1, 1); // Prints f(1)
f(0.1, 0.2); // Prints f(2)
g(1, 1); // Prints g(3)
g<int, int>(1, 1); // Prints g(3)
All this can be seen in action here - copied from @Yakk's comment.