Question

Why this is ambiguous?

template<class T> void g(T)  {}   // 1
template<class T> void g(T&) {}   // 2

int main() {
    int  q;
    g(q);
}

I understand that this is partial ordering context. And my, possibly erroneous, thinking is: any T& from #2 can be put in #1, but not any T from #1 is legit in #2. So partial ordering should work.

Was it helpful?

Solution

OK. I think this is what you're looking for. Not diving into the twice-application of the parameter vs. argument type comparison, the following in the standard leaps out at me:

C++11 §14.8.2.4p5

Before the partial ordering is done, certain transformations are performed on the types used for partial ordering:

  • If P is a reference type, P is replaced by the type referred to.
  • If A is a reference type, A is replaced by the type referred to.

C++11 §14.8.2.4p6 goes on to talk about what happens when both are reference types, but that isn't applicable here (though also an interesting read). in your case, only one is, so it is stripped. From there:

C++11 §14.8.2.4p7

Remove any top-level cv-qualifiers:

  • If P is a cv-qualified type, P is replaced by the cv-unqualified version of P.
  • If A is a cv-qualified type, A is replaced by the cv-unqualified version of A.

Now both are completely equal, and thus you have your ambiguity, which I believe is solidified from C++11 §14.8.2.4p10. The text of C++11 §14.8.2.4p9 covers both being reference types which, again, is not the case here:

C++11 §14.8.2.4p10

If for each type being considered a given template is at least as specialized for all types and more specialized for some set of types and the other template is not more specialized for any types or is not at least as specialized for any types, then the given template is more specialized than the other template. Otherwise, neither template is more specialized than the other.

But reading the standard in this section is like deciphering greek to me, so I may be way off base. (no offense to the Greeks =P).

It did, however, make me think "a const T& against a T, given the same invoke condition g(q), should also be ambiguous if everything I just read is enforced as-written." Sure enough, I tried it, and the same ambiguity was flagged.

OTHER TIPS

Your reasoning is correct when these two types are competing in a partial ordering of class template partial specializations, and it is how things work there.

But when a reference type is compared against a nonreference type, the general gist is that they are ambiguous in a call scenario if nothing else makes one be preferred over the other. That is, the kind of reference of the reference type doesn't matter in overload resolution when compared against the other, so partial ordering doesnt consider it either.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top