Question

This is a followup from function template does not recognize lvalue

Lets play with the following code:

#include <iostream>
template <class T>
void func(T&&) {
  std::cout<<"in rvalue\n";
}

template <class T>
void func(const T&) {
  std::cout<<"in lvalue\n";
}

int main()
{
    double n=3;
    func<double>(n);
    func(n);
}

It prints:

in lvalue
in rvalue

I don't understand what's happening in the second call. How the compiler resolve the template parameter ? Why isn't there any ambiguity ?

Was it helpful?

Solution

When you say func<double>(n), there's no argument deduction, since you specify the argument, and so the choice is between func(double &&) and func(const double &). The former isn't viable, because an rvalue reference cannot bind to an lvalue (namely n).

Only func(n) performs argument deduction. This is a complex topic, but in a nutshell, you have these two possible candidates:

T = double &:    func(T &&)       -->   func(double &)          (first overload)
T = double:      func(const T &)  -->   func(const double &)    (second overload)

The first overload is strictly better, because it requires one less conversion of the argument value (namely from double to const double).

The magic ingredient is the "reference collapsing", which means that T && can be an lvalue reference when T is itself a reference type (specificaly, double & && becomes double &, and that allows the first deduction to exist).

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