15

When I consider the two following overloads:

template <class... T> void f(const T&... x);
template <class T> void f(const T& x);

I have the guarantee that f(x) will always call the second function and will never lead to an ambiguity. In a sense the second version is universally prioritized compared to the first one for one argument whatever its type is.

Now consider the situation where there is a universal reference and a const reference versions of a function:

template <class T> void f(T&& x);
template <class T> void f(const T& x);

My question is: is their a universal priority between these two functions regardless of the type of x (r-value reference, reference, cv-qualifiers, pointer...) like in the previous case? (and if yes, what is the priority ?)

Vincent
  • 57,703
  • 61
  • 205
  • 388
  • 2
    I think it was [this talk](http://www.youtube.com/watch?v=T5swP3dr190) that included this. – chris Aug 16 '13 at 02:31

1 Answers1

17

There is not a universal priority between these two functions. They compete equally in the overload resolution algorithm. In general the so-called "universal reference" wins unless const T& is an exact match, and there the const T& wins.

struct A {};

int
main()
{
    f(std::declval<A>());  // calls f<A>(A&&), #1
    f(std::declval<const A>());  // calls f<const A>(const A&&), #1
    f(std::declval<A&>());  // calls f<A&>(A&), #1
    f(std::declval<A&&>());  // calls f<A>(A&&), #1
    f(std::declval<const A&&>());  // calls f<const A>(const A&&), #1
    f(std::declval<const A&>());  // calls f<A>(const A&), #2
}

Good advice is to never overload like this.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • It might be worth mentioning which of these cases (if any) #2 was never a candidate to begin with. – Ben Voigt Aug 16 '13 at 02:58
  • @BenVoigt Unless I'm missing something, both overloads are viable in all these expressions. – aschepler Aug 16 '13 at 03:19
  • @aschepler: I think you're right. Maybe it is `T&&` vs `T&` that ends up being surprising. – Ben Voigt Aug 16 '13 at 03:34
  • 2
    Note the technical term "Exact Match" (13.3.3.1.1) applies to all twelve implicit conversion sequences. Might be safer to say "wins unless the argument is a `const` lvalue". – aschepler Aug 16 '13 at 03:38
  • I'm not sure, but doesn't `f(std::declval());` actually call `f(const A&&)`? – MWid Aug 16 '13 at 08:35