12

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 ?

Community
  • 1
  • 1
hivert
  • 10,579
  • 3
  • 31
  • 56
  • 5
    You may wish to consult 14.8.2 in the Standard. Template argument deduction is a somewhat complex subject. The point is that the "best match" is chosen, and that `T` may be deduced to be a reference type. – Kerrek SB Mar 04 '14 at 09:14
  • "somewhat complex subject" ! I fully agree. By the way, is there a way to ask g++/clang++ to be verbose about what it's doing here ? – hivert Mar 04 '14 at 09:20
  • That innocent little subsection occupies 15 pages and develops a whole new mathematical notation :-S But ultimately it "does what you think", you just have to embrace template parameters as honest types in the context of a function signature. – Kerrek SB Mar 04 '14 at 09:23
  • 3
    I found this link helpful : http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers – uchar Mar 04 '14 at 09:29
  • No, it doesn't print log, or what it does. But template warnings/errors are quite verbose, if that's what you mean. – BЈовић Mar 04 '14 at 09:30
  • @omid +1; there's also a [video version](http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11). – Angew is no longer proud of SO Mar 04 '14 at 09:32

1 Answers1

16

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).

Community
  • 1
  • 1
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I think Herb Sutter's article [Why Not Specialize Function Templates?](http://www.gotw.ca/publications/mill17.htm) also helps to understand this behavior. – piwi Mar 04 '14 at 09:20
  • 3
    @piwi Except that it's hopelessly out of date since the introduction of rvalue references. @Kerrek doesn't really make it clear enough: when template argument deduction is taking place, the `&&` in `func( T &&` ) is **not** an rvalue reference, but a universal reference, which can become either an rvalue reference (if the argument is an rvalue) or an lvalue reference (if the argument is an lvalue). Scott Meyer explains this well in http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers; that's the article I'd recommend for this particular question. – James Kanze Mar 04 '14 at 09:33
  • @JamesKanze I am aware of the double meaning of `&&`, depending on the context, but you're right that Herb Sutter's article does not cover this; however, I found it useful to understand resolution rules when "mixing" templates and overloads. Thanks for the link! – piwi Mar 04 '14 at 09:37
  • @piwi It's definitely a useful article, and very well written. It just doesn't address the behavior in question here (mainly because the behavior didn't exist when the article was written). – James Kanze Mar 04 '14 at 09:40
  • @JamesKanze: I linked to another answer which already spelt out all the details, I didn't want to repeat them here... – Kerrek SB Mar 04 '14 at 09:41
  • @JamesKanze So... I guess I was confused with this behavior as well then :-) Thanks for the clarification! – piwi Mar 04 '14 at 09:45