As mentioned in other answers, the reason is that the signature of the
explicit function specialization is not taking part in overload
resolution.
A simple rule of thumb for explicit specializations is that they change the the definition that will be used when it's primary template is called with the specific template arguments.
template <typename T> void foo (T) {
// definition used for 'foo' when T is not 'int'
}
template <> void foo<int> (int) {
// definition used for 'foo' when T is 'int'
}
The compiler performs the following steps when selecting the best swap
(I'll ignore exception specifications for brevity):
namespace A
{
template <typename T> struct Foo { };
template <typename T> void swap (Foo<T> &, Foo<T> &);
}
namespace std
{
// swap provided by the STL
template <typename T> void swap (T &, T &);
// explicit specialization of std::swap
template <> void swap (Foo<int> &, Foo<intT> &) { }
}
Specializations of the primary templates are generated for both swaps
:
13.3.1p7: In each case where a candidate is a function template,
candidate function template specializations are generated using
template argument deduction (14.8.3, 14.8.2). Those candidates are
then handled as candidate functions in the usual way.
NB: The explicit specialization is not part of this.
For swap(a,b)
the candidate set used by overload resolution will
contain the following generated function template specializations:
A::swap(Foo<int>&, Foo<int>)&);
std::swap(Foo<int>&, Foo<int>)&);
Both are generated template specializations and both have exactly the same conversion sequences for the arguments so to determine which template to use the following bullet in the Best Viable Function says:
13.3.3p1b7: F1 and F2 are function template specializations, and the
function template for F1 is more specialized than the template for
F2 according to the partial ordering rules described in 14.5.6.2.
Partial ordering comes down to comparing the function parameter lists to find which is more specialized. In this example, Foo<T>
is more specialized than T
and so swap(Foo<T>&, Foo<T>&)
is considered a better match than swap(T&,T&)
. The result is that A::swap
is selected and so the explicit specialization of std::swap
is ignored.
If the code is changed so the explicit specialization is for A::swap
rather than std::swap
then as A::swap
wins overload resolution, then the explicit specialization will be used:
namespace A
{
template <typename T> struct Foo { };
template <typename T> void swap (Foo<T> &, Foo<T> &);
// explicit specialization of A::swap
template <> void swap (Foo<int> &, Foo<intT> &) { }
}