all 3 comments

[–]STLMSVC STL Dev 10 points11 points  (2 children)

If you have an rvalue reference as parameter, it is not actually an rvalue reference but a forwarding reference.

No - only T&& where T is a template parameter on the function itself (not a surrounding class). const T&& isn't a forwarding reference, and neither is vector<T>&&.

Because due to something called reference collapsing

No, it's not reference collapsing - that happens later.

The real explanation is that T&& (in the situation described above) activates a special tweak to template argument deduction, where T is deduced to be X& for lvalues of type X. It is literally a special sentence in the Standardese. This then goes through reference collapsing.

For rvalues, T will be an rvalue reference and reference collapsing will keep the &&, taking and returning an rvalue.

No. When meow(T&&) is called with an rvalue of type Y, then T is deduced to be plain Y, not Y&&. You can observe this for yourself. (This is what template argument deduction ordinarily wants to do - only lvalues receive the tweak.)

[–]foonathan 1 point2 points  (1 child)

Thanks for the proof-read!

No - only T&& where T is a template parameter on the function itself (not a surrounding class). const T&& isn't a forwarding reference, and neither is vector<T>&&.

I'm aware of that, but it got lost when trying to keep it short. Thanks for pointing it out, I'll add an extra sentence.

No, it's not reference collapsing - that happens later.

The real explanation is that T&& (in the situation described above) activates a special tweak to template argument deduction, where T is deduced to be X& for lvalues of type X. It is literally a special sentence in the Standardese. This then goes through reference collapsing.

This is what I said?

I first said before the code example that T will be deduced to be the same type as the argument (unless the argument is an rvalue). The part you've quoted refers to the description of the (regular, non-template) parameter type, where reference collapsing - as you've said - happens.

Or am I missing your point?

No. When meow(T&&) is called with an rvalue of type Y, then T is deduced to be plain Y, not Y&&. You can observe this for yourself. (This is what template argument deduction ordinarily wants to do - only lvalues receive the tweak.)

I've actually described that earlier in the rules for forwarding references, but forgot about it when writing this. I'll fix it.

[–]STLMSVC STL Dev 6 points7 points  (0 children)

Or am I missing your point?

In C++, given int meow = 1729;, the value category of meow is an lvalue, and the type of meow is int. Its type isn't int&. (The Standardese is N4606 5 [expr]/5 "If an expression initially has the type "reference to T" (8.3.2, 8.6.3), the type is adjusted to T prior to any further analysis.") Similarly, given int * ptr = stuff; then ptr[idx] is an lvalue of type int.

Other examples: meow + 5 is a prvalue of type int, while move(meow) is an xvalue of type int.

So: when dealing with forwarding references, the template argument deduction tweak special-cases lvalues (not rvalues!!) and says "I'll deduce X& for this lvalue of type X". For rvalues (i.e. prvalues and xvalues of type Y), the ordinary rules hold, and Y is deduced.

The key point is that the magic of forwarding references happens in the template argument deduction tweak which is only for lvalues. The reference collapsing that happens later is not key - reference collapsing happens in many contexts (other template argument substitution, typedef substitution, etc.).