6

Why, in the below, is the call to an instantiation of bar not ambiguous, while the non-template overloaded function foo is ambiguous. It is the same for nullptr instead of NULL

#include <iostream>

template<typename T>
void bar (T*)
{
  std::cout << "bar(T*)" << std::endl;
}

template<typename T>
void bar (typename T::value_type *)
{
  std::cout << "bar(T::value_type*)" << std::endl;
}

struct A
{
  using value_type = int;
};

void foo (A::value_type*)
{
  std::cout << "foo(A::value_type *)" << std::endl; 
}

void foo (A*)
{
  std::cout << "foo(A *)" << std::endl; 
}

int main ()
{
  bar<A> (NULL);
  foo (NULL); // ambigous
}

EDIT: To be clear. I expect the foo overload to be ambiguous. I don't understand why the bar overloads generated when I instantiate bar<A> are not equally ambiguous.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I am surprised because I specify A as the type, which I would expect to generate two overloads for `bar`, one taking an A* and one taking an int*, the same as with `foo`. Why would one be preferred over the other? Especially in the case of `nullptr` – danielgharvey Jul 20 '15 at 15:37
  • @VictorPolevoy Explicitly specifying the type just means there's no template type deduction happening - it doesn't mean that it can't be ambiguous. – Barry Jul 20 '15 at 15:47
  • I find it odd that this was closed by the same person who posted an answer to it just moments before... – defube Jul 20 '15 at 15:49

2 Answers2

1

The rules for determining which overload is the best viable candidate as the last tiebreaker include, from [over.match.best]:

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— [...]
— 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.

That bullet point is reached only if we have two functions with identical conversion sequences in which either both are or both aren't function templates. For foo, both our overload candidates have identical conversion sequences, neither are function templates, and this last bullet point doesn't apply - so it's ambiguous.

For bar though, we can try to see if one or the other of

template<typename T> void bar (T*) // (1)
template<typename T> void bar (typename T::value_type *) // (2)

is more partially specialized than the other. The rules for that are basically to try to see if you can call one function with the other's argument. In this case, any typename T::value_type* is still a pointer, so you could call the T* overload with it. However, in the other direction, template deduction would fail as typename T::value_type is a non-deduced context. So (2) is considered more partially specialized and so it's chosen as the best viable candidate. No ambiguity.

Barry
  • 286,269
  • 29
  • 621
  • 977
0

There's an additional rule when it comes to resolving ambiguity between function overloads that are instantiations of a function template: partial ordering of overloaded function templates ([temp.func.order]).

This is usually used to resolve ambiguity in favor of more specialized overloaded function templates:

template<typename T> void f(T) { ... }
template<typename T> void f(T*) { ... } // specialization for pointers
void g() { int i; f(&i); }   // calls f<int>(int*), not f<int*>(int*)

However, because of the way the rules are set out ([over.match.best]/1) function template partial ordering applies even when the template parameter (here T := A) was not deduced from the arguments by template argument deduction, even if it was supplied by explicit specialization:

[...]
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.

Here bar(A::value_type *) is considered more specialized than bar(A *) (under [temp.func.order]), so the former is preferred and there is no ambiguity.

ecatmur
  • 152,476
  • 27
  • 293
  • 366