17

Naturally, this won't compile:

int &z = 3; // error: invalid initialization of non-const reference ....

and this will compile:

const int &z = 3; // OK

Now, consider:

const int y = 3;
int && yrr = y; // const error (as you would expect)
int && yrr = move(y); // const error (as you would expect)

But these next lines do compile for me. I think it shouldn't.

int && w = 3;
int && yrr = move(3);
void bar(int && x) {x = 10;}
bar(3);

Wouldn't those last two lines allow the literal 3 to be modified? What is the difference between 3 and a const int? And finally, Is there any danger with 'modifying' literals?

(g++-4.6 (GCC) 4.6.2 with -std=gnu++0x -Wall -Wextra)

outis
  • 75,655
  • 22
  • 151
  • 221
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 1
    To answer my own question: In `move(3)` maybe the 3 is copied first to create a temporary int will be destroyed at the end of the statement. Is this the explanation? – Aaron McDaid Dec 22 '11 at 01:37
  • In your second statement: const &z = 3; you are missing the type specifier. so it doesn't compile. – C.J. Dec 22 '11 at 01:38
  • Thanks, @CJohnson, I normally copy and paste working code in here. But I was careless with that one liner! – Aaron McDaid Dec 22 '11 at 01:39
  • 1
    Note that cv-[qualifiers](http://stackoverflow.com/questions/3610943/) don't really apply to non-class rvalues. Rather than "const", "mutable" is the more appropriate term to use. – outis Dec 22 '11 at 02:36

1 Answers1

13

The rvalue reference to the literal 3:

int && w = 3;

is actually bound to a temporary that is the result of evaluating the expression 3. It's not bound to some Platonic literal 3.

(all the following standards references are from the March 2011 draft, n3242)

3.10/1 "Lvalues and rvalues"

The value of a literal such as 12, 7.3e5, or true is also a prvalue

Then 8.5.3 "References" gives the rules for how a reference is bound falls through to the last case, which says:

Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy-initialization (8.5). The reference is then bound to the temporary.

and gives as one example something very close to what's in your question:

double&& rrd = 2; // rrd refers to temporary with value 2.0
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Thanks, but if that was true, then shouldn't this work? `move(3) = 6;` Instead I get an error "*error: using xvalue (rvalue reference) as lvalue*". It's time for me to read up on xvalues and prvalues and all that again :-) – Aaron McDaid Dec 22 '11 at 01:57
  • 3
    Thanks to your answer, I think I can answer my comment of a few seconds ago. I can see that `move(3)` is an rvalue (clearly, it's unnamed). Whereas inside my function `void bar(int && x) {x = 10;}` there is a name for `x`. This seems to be the difference between `x=6` and `move(3)=6`. Both are `&&` but one is an lvalue and the other is not. And this distinction is what leads to the error message for `move(3)=6`. – Aaron McDaid Dec 22 '11 at 02:06
  • @Aaron: (A late) addition to your comment: Somewhere, the standard specifies that a named rvalue is an lvalue, so yes, that's exactly how it works. :) – Xeo Jan 11 '12 at 04:20