12

With the 3 following overloads

template <class T> auto foo() { return 1; }
template <class T> int  foo() { return 2; }
template <class T> T    foo() { return 3; }

Is the following ill formed ?

static_cast<int(*)()>(&foo<int>)();

Clang selects overload #2, whereas gcc fails to compile (Demo)

When removing overload #1, both agree to select overload #2 (Demo).

When removing overload #2, gcc selects overload #1 and clang fails to compile (Demo)

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 6
    Isn't defining 1 and 2 in the same translation unit an ODR violation? – user657267 Dec 16 '16 at 01:28
  • If "auto" is translated as "int" then #1 and #2 are the same, yes? Not prefered candidate. Clang seems to consider #2 more specialized than #1 and #1 and #3 the same specialization; ambiguous selection again. I would say that gcc is right and Clang is wrong due to "auto" should not participate in overload resolutions. – Ripi2 Dec 16 '16 at 01:58
  • 2
    @user657267 Return types are part of function templates' signatures. The above declarations provide different *declared* return types, so the signatures differ. That the actual return types coincide is irrelevant. – Columbo Dec 16 '16 at 02:14
  • Great question. +1 – skypjack Dec 16 '16 at 06:53

1 Answers1

9

As per [over.over]/2, we perform template argument deduction. This will succeed for all three overloads: in the first one, keep [temp.deduct.funcaddr]/2 in mind:

A placeholder type (7.1.7.4) in the return type of a function template is a non-deduced context. If template argument deduction succeeds for such a function, the return type is determined from instantiation of the function body.

Since the deduction will succeed (given that all template parameters have explicitly supplied arguments), the return type is deduced as int. In the second case, deduction succeeds since the argument is provided, and in the third, T will be deduced.

Going on to paragraph 4,

If more than one function is selected, [...] any given function template specialization F1 is eliminated if the set contains a second function template specialization whose function template is more specialized than the function template of F1 according to the partial ordering rules of 14.5.6.2. After such eliminations, if any, there shall remain exactly one selected function.

According to [temp.deduct.partial]/3, the function templates' function types are used for partial ordering. We can immediately see that #1 and #2's function types do not contain any template parameters that participate in deduction, hence via the addition to [temp.deduct.partial]/4 introduced by core issue 1391's resolution, their corresponding Ps are not used to determine the ordering. @bogdan explained here why that resolution is problematic; the bottom line is that ordering just yields an ambiguity for #1 and #2.

That is, according to current (probably defective) wording, the conversion is ill-formed in all cases. If partial ordering is fixed for pairs of non-dependent/deducing parameters,

  • case 1 and 3 are ambiguous, because for two non-dependent function types (the ones of #1 and #2), there is no ordering pair.
  • the accepting behavior in case 2 is correct (as expected).

[temp.deduct.type]/8 element 9 (T()), in case you were curious.

Community
  • 1
  • 1
Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Chapeau. Really interesting. You know the standard by heart and it scares me a bit anyway... :-) +1 – skypjack Dec 16 '16 at 06:52