1

This question asks if all temporaries are rvalue.

The answer is no, because if we consider this expression:

const int &ri = 2 + 3;

then, the very same temporary (2 + 3), which is an rvalue here, can be used as an lvalue in a subsequent expression:

const int *pi = &ri;

so this temporary is not (only) an rvalue.

The logic statement temporary ==> rvalue is then false.

However, we cannot write

const int &ri = &(2 + 3); // illegal, 2 + 3 -> temporary -> rvalue

or

int *i = &4; // illegal, 4 is an rvalue (literal)

or

int foo();
int *i = &foo(); // illegal, foo() -> temporary -> rvalue

Thus my question is, can we generate an rvalue in a certain expression without having a temporary or a literal? Is rvalue ==> (temporary or literal) true?

Community
  • 1
  • 1
Vincenzo Pii
  • 18,961
  • 8
  • 39
  • 49

2 Answers2

5

Expressions that yield temporary objects are r-values. There's a special rule which allows const-references and r-value references to bind to r-values, and this extends the lifetime of the temporary object to that of the reference (see 12.2(5)), but that does not make the temporary-object expression any less of an r-value.

However, once bound to a reference, the reference variable itself has a name, and thus the reference expression is an l-lvalue.

Don't confuse expressions, variables and objects.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 5
    *Don't confuse expressions, variables and objects*: Correct. *l-value* and *r-value* apply to *expressions*. Temporaries are not *r-values*, an expression that yields a temporary *is* an *r-value expression* – David Rodríguez - dribeas Nov 03 '12 at 02:16
  • @DavidRodríguez-dribeas: Yes, indeed -- well said. – Kerrek SB Nov 03 '12 at 02:30
  • What 12.2(5) says, confirms that `temporary ==> rvalue` is false and that is ok. But still I don't have an example that shows that `rvalue ==> (temporary or literal)` is false. As I said to David, I'm not challenging, but just trying to understand if that assertion (`rvalue ==> (temporary or literal)`) can be made. Thanks. – Vincenzo Pii Nov 03 '12 at 10:57
  • 1
    @VincenzoPii: Lots of things are rvalues. For example, decayed C array names. Or `this`. Or the result of a certain static cast. – Kerrek SB Nov 03 '12 at 17:16
  • 1
    @VincenzoPii: Adding to those examples, an *lvalue* expression used in a context where an *rvalue* is needed will be converted to an *rvalue* with the (obviously named): *lvalue to rvalue conversion*. `int a = 5; int b = 1+a;`, the subexpression `a` is an *lvalue* that will be converted to an *rvalue*, so in this particular usage `a` is an *rvalue*, as I mentioned before: consider that an *lvalue* is a reference to a real object, while an *rvalue* is just a value (that might or not be stored inside an object). – David Rodríguez - dribeas Nov 05 '12 at 15:24
3

The rvalue and lvalue attributes apply to expressions, not to objects. An expression can be either an lvalue or an rvalue. Oversimplifying a expression that yields a value is an rvalue-expression and an expression that yields an object is an lvalue-expression. The lvalue to rvalue conversion is the act of reading the value out of an object.

A expression that yields a temporary and a literal are both rvalue-expressions they represent a value not an actual object.

In your example:

const int &ri = 2 + 3;
const int *pi = &ri;

The expression 2+3 is an rvalue-expression used to initialize a constant reference. That, according to the language implies the extension of the lifetime of the temporary beyond the current expression and until the reference goes out of scope. After that, in the second expression, the subexpression ri is an lvalue-expression that refers to the temporary object, whose lifetime has been extended.

Note that there are other ways of creating rvalue expressions with temporaries, for example calling a member that yields a reference:

struct test {
   test& thisTest() { return *this; }
};
test foo();
... foo().thisTest()

The subexpression foo() is an rvalue-expression, but the expression foo().thisTest() is an lvalue-expression. Both of them refer to a temporary object that will disappear at the end of the full expression.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Thank you for your answer. In your last example, you demonstrate that `temporary ==> rvalue` is false, but not that `rvalue ==> (temporary or literal)` is false. Is it necessary to have a temporary or a literal to yield to an rvalue? I'm not challenging you, just willing to understand if we can make such an assertion :). – Vincenzo Pii Nov 03 '12 at 10:51
  • @VincenzoPii: You are missing the point. *rvalue* and *lvalue* apply to expressions, not to *objects*. An object that is not a temporary can be used in the context where an *rvalue* is needed, and that will trigger the *lvalue-to-rvalue* conversion and you will be using an object as an *rvalue*. The *r/l-value* is only related to the temporary/named objects in that expressions that involve one or the other tend to be of the same type. For an unrelated car example: Jaguar/Volkswagen are unrelated to gas/diesel, although there is only one Jaguar diesel model (so they are not 100% orthogonal) – David Rodríguez - dribeas Nov 05 '12 at 01:57
  • Thank you very much for the explanation, it is perfectly clear now! – Vincenzo Pii Nov 05 '12 at 18:56