1

For this code (available at http://ideone.com/Mo7fQr)

template<typename T>
void f(const T&) { std::cout << "const T& overload\n"; }

template<typename T>
void f(T&&) { std::cout << "T&& overload\n"; }

int main()
{
  const int x = 0;

  f(x);                 // calls const T& overload
  f(std::move(x));      // calls T&& overload
}

the first call to f (with an lvalue) calls the const T& overload, while the second call (with an rvalue) calls the T&& overload. At least that's what happens with gcc 4.8.1 and the most recent VC++ (VC12).

I think I understand why the second call resolves as it does: because the first template instantiates to taking a const int& parameter, while the second template instantiates to taking a const int&& parameter, and because the argument passed at the call site is an rvalue, it preferentially binds to the rvalue reference. (I believe this is specified in the C++11 standard at 13.3.3.2/3 bullet 1 sub-bullet 4.)

But for the first call to f, both templates instantiate to taking a parameter of type const int&. So why is the first template preferred when a const lvalue is passed in?

KnowItAllWannabe
  • 12,972
  • 8
  • 50
  • 91

1 Answers1

1

When the same function template specialization can be generated from more than one declaration, the declarations are disambiguated using partial ordering of function templates as described in the C++11 standard ยง14.5.6.2 Partial ordering of function templates [temp.func.order]. The compiler determines which of the templates is the most specialized and prefers it.

In your example, the const T& overload of f is more specialized than the T&& overload. Intuitively, T&& can be deduced to anything that const T& can, but not vice versa, so const T& is more specific and therefore its function overload is more specialized.

Casey
  • 41,449
  • 7
  • 95
  • 125
  • How can `T const&` not match anything `T&&` can? Got an example? (I think it actually *can* match anything, but would require qualification-adjustment for some things, like non-const lvalues and rvalues. Also, for rvalues, `T&&` is preferred over `T const&`, so that's that.) โ€“ Xeo Jul 20 '13 at 07:40
  • @Xeo e.g., `T const&` can't deduce `int&` or `int&&`. If you tried to call `f` with an `int&` parameter, the `f(const T&)` overload is specialized to `f(const int&)` - notably not `f(int&)` - and requires a conversion sequence `int&` -> `const int&`. โ€“ Casey Jul 20 '13 at 07:45
  • I replaced "match" with "be deduced to" in the answer, think it's a bit more clear. โ€“ Casey Jul 20 '13 at 07:53