Sorry to reply to my own post, but after reading some of the other
replies on comp.lang.c++ I thought it worth adding some more info. The
partial ordering rules for function templates are given in section
14.5.5.2 of the C++ standard. In particular:
14.5.5.2/4: "... The transformed template is at least as specialized
as the other if, and only if, the deduction succeeds
and the deduced parameter types are an exact match (so the deduction
does not rely on implicit conversions)."
14.5.5.2/5: "A template is more specialized than another if, and only
if, it is at least as specialized as the other template
and that template is not at least as specialized as the first."
You're quoting out of context. '14.5.5.2 is incredibly
difficult to understand, but one thing is clear: it establishes
a partial ordering over the function templates themselves,
independantly of the actual instantiations.
So in the case presented by the original post, since there are no
implicit conversions needed for either function, neither is considered
more specialized than the other and the overload is ambiguous.
Whether implicit conversions are needed or not for a specific
call has nothing to do with the ordering between the function
templates. In fact, the ordering between the function templates
is only considered if overload resolution would otherwise be
ambiguous. I'm reading '14.5.5.2 for the third time now in this
thread, and I'm gradually starting to understand what it is
saying. Basically, for each function template, the compiler
generates a unique imaginary argument for each template
parameter, and considers the resulting instantiation. If type
deduction for another function template succeeds with this
instance, then the function template in question is at least as
specialized as the function template for which type deduction
succeeded. This is an ordering relationship, which could be
symbolized by <=; i.e. for function templates x, y, x <= y IFF x
is at least as specialized as y. (Note that this ordering can
be established between any two function templates, regardless of
name or parameters, but it is only used in overload resolution,
which only concerns function templates with the same name.) In
overload resolution, if the call is otherwise ambiguous, and x
<= y, but !( y <= x ) (i.e. x < y), then overload resolution
chooses x.
The ordering is partial, and in this case, we have neither foo/1
<= foo/2 nor foo/2 <= foo/1. If the compiler instantiates foo/1
with some arbitrary, imaginary, non pointer type, type deduction
fails for foo/2, and if the compiler instantiates foo/2 with two
different imaginary T1 and T2, type deduction fails for foo/1.
So the two foo are unordered.
Note how this is different from:
template<typename T>
void foo(T,T){}
template<typename T>
void foo(T*,T*){}
int main( ) {
foo((int*)0,(int*)0);
}
In this case, too, both foo are "exact match" once type
deduction has occured. But in this case, foo/2 is unambiguously
more specialized than foo/1; if foo/2 is instantiated with some
imaginary type T, type deduction works for foo/1, but if foo/1
is instantiated with some imaginary (non-pointer) type T,
type deduction fails for foo/2.
Again, this ordering is over the function templates themselves,
independant of any instantiations.
(I'm sorry if I'm over explaining things here, but trying to
explain it in such detail is helping me to understand it.)