3
// 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?

olist
  • 877
  • 5
  • 13
  • For the first call the mechanism at play is ordinary value conversion for the argument, for ordinary function overload resolution. Both (non-) conversions are apparently equally good. For the second call the mechanism at play is function template argument deduction. Here one wins, because it's an *exact match*. Sorry that I can't give you a full answer down to the detail level, but this is the direction to look for that answer: that the mechanisms at play are very different, with different rule sets. – Cheers and hth. - Alf Sep 03 '17 at 01:55

3 Answers3

5

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

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • The OP claims the *first* template is called, which disagrees with your answer (and is surprising to me). Is the OP incorrect in this claim? Did I read the OP wrong? Or is something strange going on? – Yakk - Adam Nevraumont Sep 03 '17 at 02:19
  • @Yakk: Yep, that OP's claim is wrong. (I didn't notice it in my original comment on the question.) – Cheers and hth. - Alf Sep 03 '17 at 02:19
  • @Yakk I don't think it's claiming that the first one *is* called; it's claiming that the first one *can be* called - or, is viable - by deducing `T = int *` ("another test"). – T.C. Sep 03 '17 at 02:20
2

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.

fefe
  • 3,342
  • 2
  • 23
  • 45
0

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 &) {}
iBug
  • 35,554
  • 7
  • 89
  • 134