Why aren't these overloads ambiguous?
Asked Answered
H

1

7

The following code compiles fine with gcc and clang.

template <typename T>
struct identity
{
    typedef T type;
};

template <typename T>
void foo(typename identity<T>::type);

template <typename T>
void foo(T);

int main()
{
    foo<int>(0);
}

It looks like overload resolution is choosing the first overload (the identity<T>::type one).

Could someone explain why the overloads aren't ambiguous? As far as I can tell, the only difference between them is that the argument of the first one is a non-deduced context and the argument of the second one isn't, but since I'm providing the template argument explicitly, I don't see why that should matter.

Hyperthyroidism answered 26/5, 2013 at 22:29 Comment(1)
Interesting. Obviously the second function would have been chosen if you had enabled type deduction by not explicitly instantiating foo<int>(0) but foo(0) instead (No type deduction for the identity meta function). @Andy Prowl: I dont want to question your answer put point out that your reasoning is not as obvious as it may appear. Give the foo parameter a default value and call foo<int>() without parameter. Your argumentation should still apply but now the overloads are indeed ambiguous as HighCommander4 expected. Explicit template instantiation of function templates is complicated.Gandy
S
7

Both overloads are viable, but the former is more specialized than the latter, and therefore it gets picked by overload resolution.

Per paragraph 13.3.3/1 of the C++11 Standard on overload resolution:

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

— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

— the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ ... ] or, if not that,

F1 is a non-template function and F2 is a function template specialization, or, if not that,

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.

The process of determining which of two function templates is more specialized than the other is outlined in paragraph 14.5.6.2/2:

Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process.

Shuma answered 26/5, 2013 at 22:32 Comment(1)
Makes sense, thanks! (I intuitively thought of "more specialized than" as meaning "applies to a smaller set of input types", which is what I think the intention is, but I see how the technical definition of the term doesn't mean exactly that.)Hyperthyroidism

© 2022 - 2024 — McMap. All rights reserved.