Reputation: 1039
// g++(5.4)
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {}
template <typename T> void tfunc(T *) {}
int main()
{
int a = 0;
func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
According to my another test, tfunc(&a)
instantiates the first template to void tfunc(int * const &)
which has the same parameter type as the first nontemplate.
So, why is the first call ambiguous but the second not?
Upvotes: 3
Views: 68
Reputation: 3432
There are some special rules in overload resolution for template functions, one of them is :
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.
See this question about how to determine which function template is more specialized.
Here, as the second template function is more specialized, there is no ambiguation.
#include <iostream>
void func(int * const &) {}
void func(int *) {}
template <typename T> void tfunc(const T &) {std::cout << "#1\n";}
template <typename T>void tfunc(T *) {std::cout << "#2\n";}
int main()
{
int a = 0;
//func(&a); // ambiguous
tfunc(&a); // unambiguous
return 0;
}
// output: #2
Edit: Though a test in https://ideone.com/C9rF8b , we can see that the second template is chosen, not the first one as stated in the question.
Upvotes: 2
Reputation: 37227
Because a const pointer and a non-const pointer (i.e. T * const
and T *
) makes no difference if they appear in a function's parameters, and so does passing by value (by copy) and passing by const reference. That's the reason why f(&a)
is ambiguous.
For the second one, since &a
is resolved to int *
, the second template matches better because it's more specialized (it can't accept non-pointer arguments). The first template is more general so it's not used.
If you change the first template function to this it will also be ambiguous:
template <typename T>
void tfunc(T * const &) {}
Upvotes: 0
Reputation: 137315
Given two function templates that are otherwise equally as good, overload resolution will select the more specialized function template, using a procedure commonly known as partial ordering. The exact rules are pretty complicated, but essentially it tries to determine if the set of arguments template A can be called with is a (proper) subset of the set of arguments template B can be called with. If so, then A is more specialized than B, and overload resolution will prefer A.
Thus, in your case, tfunc(const T&)
can be called with ~everything; tfunc(T*)
can only be called with pointers. The latter is more specialized, and is therefore selected.
If you are interested in the standardese and detailed rules, see [temp.func.order] and [temp.deduct.partial].
Upvotes: 5