Is binding non-const references to temporaries the sole key featureof rvalue references?

K

K. Frank

Hello Group!

Is the ability to bind a non-const reference to a
temporary the only important feature / benefit of
rvalue references?

Please note, I am not asking what it is that rvalue
references let you do; I am asking what specific
capability of rvalue references lets you do those
things.

Asked another way, if we were to permit regular
non-const references to bind to temporaries (I'm not
saying we should.), would there remain any need to
introduce rvalue references into the language?

Basic illustration:

// int& nr = 1; // illegal: non-const reference to temporary
const int& cr = 2; // const reference okay
int&& rr = 3; // non-const rvalue reference okay


Thanks for any insight.


K. Frank
 
N

Norman J. Goldstein

Hello Group!

Is the ability to bind a non-const reference to a
temporary the only important feature / benefit of
rvalue references?

Please note, I am not asking what it is that rvalue
references let you do; I am asking what specific
capability of rvalue references lets you do those
things.

Asked another way, if we were to permit regular
non-const references to bind to temporaries (I'm not
saying we should.), would there remain any need to
introduce rvalue references into the language?

Basic illustration:

// int& nr = 1; // illegal: non-const reference to temporary
const int& cr = 2; // const reference okay
int&& rr = 3; // non-const rvalue reference okay


Thanks for any insight.


K. Frank

Another feature of rvalue references is when matching template
arguments. For example,

template< T arg >
void foo( T&& arg );

will of course match an rvalue reference, but will also match the
following situation:

T a;
T& ar = a;
foo( ar );

( http://thbecker.net/articles/rvalue_references/section_07.html )
 
N

Norman J. Goldstein

Another feature of rvalue references is when matching template
arguments. For example,

template< T arg >
void foo( T&& arg );

will of course match an rvalue reference, but will also match the
following situation:

T a;
T& ar = a;
foo( ar );

( http://thbecker.net/articles/rvalue_references/section_07.html )
I apologize for following up to my own response. But my response does
not address the right question. To my understanding, rvalue references
allow to implement the "move" assignments and constructors. I think it
would be risky to distinguish "move" from "copy" using only non-const
and const lvalue references.
 
K

K. Frank

Hi Norman!

I apologize for following up to my own response. But my response does
not address the right question. To my understanding, rvalue references
allow to implement the "move" assignments and constructors. I think it
would be risky to distinguish "move" from "copy" using only non-const
and const lvalue references.

Please let me see if I can understand the issue you
raise.

If one were to try to implement move semantics with
regular references that were modified to support
binding non-const references to temporaries, then
one would have no way to distinguish the following
two situations:

A a; // some class we want to be able to "move"
A makeA(); // e.g., a factory function
A b; // some instance of an A

a = makeA(); // case 1: would like to move
a = b; // case 2: don't move, b should remain valid

Without two kinds of references (i.e, regular references
and rvalue references) we would have no way to treat cases
1 and 2 differently. Is that the point? In more detail,
if we let regular references bind to temporaries (and had
no rvalue references), then either we could use the regular
reference for the move, but then we would incorrectly move
b in case 2, or we could use the regular reference for the
copy, but then we would use a copy in case 1, forgoing the
benefits of the move.

If so, then I would say:

Rvalue references have two key features: they support
binding of non-const references to temporaries; and they
are different (in this regard) from regular references,
so that they can be used to distinguish moves from copies,
as in the above example.

(Separately from move semantics, am I right that one could
implement perfect forwarding just by permitting non-const
regular references to bind to temporaries, or are two distinct
types of references also necessary for perfect forwarding?)


Thanks for any additional explanation.


K. Frank
 
S

SG

Am 14.07.2013 22:20, schrieb K. Frank:
If so, then I would say:

Rvalue references have two key features: they support
binding of non-const references to temporaries; and they
are different (in this regard) from regular references,
so that they can be used to distinguish moves from copies,
as in the above example.

Right. They support binding of non-const references to temporaries
(rvalues) and they can be used to distinguish between lvalues and
rvalues which is very important for the whole move semantics stuff:

void foo(const int& ref); // #1 for lvalues (and rvalues)
void foo(const int&& ref); // #2 for rvalues (preferred)

int main() {
int i = 1729;
foo(i); // pixks #1, ref will refer to i
foo(23); // picks #2, ref will refer to temporary
foo(i+0); // picks #2, ref will refer to temporary
}

Function #1 in isolation would also "eat" rvalues due to the const. But
overload resolution prefers an rvalue reference for rvalues if
everything else (type including cv-qualification) is deemed an equally
good match.

In addition to that, they have a funny template argument deduction rule
attatched to them:

template<class T> // Be aware! A very special deduction
void foo(T&& ref); // rule kicks in here in this situation!

int main() {
int i = 1729;

// deduction | reference collapsing
// ----------+---------------------
foo(i); // T=int& | T&&=int&
foo(23); // T=int | T&&=int&&
foo(i+0); // T=int | T&&=int&&
}

The deduction rule might make T an lvalue reference, see first case. The
reference collapsing rules turn T&& also into an lvalue reference in
this case. So, this kind of function template makes a
grab-it-all-and-also-preserve-the-value-category-as-part-of-the-type
function. This is deliberate and supports what is known as "perfect
forwarding".

Basically, that's all the low-level details about rvalue references.
Everything else (move semantics, perfect forwarding) builds on that.

Cheers!
SG
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top