Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is function overload ambiguous, but template overloads not ambiguous? [duplicate]

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.

like image 333
danielgharvey Avatar asked Jul 20 '15 15:07

danielgharvey


People also ask

How is function overloading different from template?

Template Function Overloading:The name of the function templates are the same but called with different arguments is known as function template overloading. If the function template is with the ordinary template, the name of the function remains the same but the number of parameters differs.

When a function is overloaded is ambiguous?

In Function overloading, sometimes a situation can occur when the compiler is unable to choose between two correctly overloaded functions. This situation is said to be ambiguous. Ambiguous statements are error-generating statements and the programs containing ambiguity will not compile.

How are overloaded functions and function templates alike How are they different?

Function overloading is used when multiple functions do similar operations; templates are used when multiple functions do identical operations. Templates provide an advantage when you want to perform the same action on types that can be different.

Can the function templates be overloaded?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.


1 Answers

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.

like image 168
Barry Avatar answered Oct 21 '22 06:10

Barry