Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why a template function accepts l-value to bind with r-value reference? [duplicate]

I'm still confused by the rules invented to support moving and forwarding. One thing I'm still not sure about is:

Is a forwarding reference just an rvalue reference (with reference collapsing rules applied)?

If it is an rvalue reference, then why does the function:

template<typename T>
void func(T&&);

accept not only rvalues, but also lvalues?

like image 533
beginpluses Avatar asked Apr 10 '26 06:04

beginpluses


2 Answers

Before T is substituted, T && is an rvalue reference (obviously).

After T is substituted (and after references are collapsed), T && either remains an rvalue reference (if T is not a reference), or becomes an lvalue reference (if T is an lvalue reference).

like image 109
HolyBlackCat Avatar answered Apr 12 '26 20:04

HolyBlackCat


I'm not sure if this answer will satisfy you, but I can point out the relevant parts of the standard. In a nutshell, the reference T&& is "grammatically" always an rvalue reference, but sometimes the type it ends up declaring is an lvalue reference type.

When this happens as the result of template argument deduction, the entire construct is called "forwarding reference", as a convenient shorthand. (This circumstance requires reference collapsing, but template argument deduction is not the only time reference collapsing happens.)

Now, on to the standard wording. First we have [dcl.ref] (e.g. p2, p6):

A reference type that is declared using & is called an lvalue reference, and a reference type that is declared using && is called an rvalue reference. [...]

If a typedef-name (9.1.3, 13.1) or a decltype-specifier (9.1.7.2) denotes a type TR that is a reference to a type T, an attempt to create the type “lvalue reference to cv TR” creates the type “lvalue reference to T”, while an attempt to create the type “rvalue reference to cv TR” creates the type TR. [Note: This rule is known as reference collapsing. — end note]

Finally, the case of template argument deduction is handled in [temp.deduct.call]p3:

A forwarding reference is an rvalue reference to a cv-unqualified template parameter [...]

In other words, a forwarding reference is an rvalue reference, but it's one that accepts lvalues, too. (Note that the standard's definition of "forwarding reference" doesn't actually require the template argument to be deduced, although that is the primary way in which you would usually want to trigger the reference collapsing behaviour.)

like image 26
Kerrek SB Avatar answered Apr 12 '26 20:04

Kerrek SB



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!