-2

I am trying to understand and read that rvalues cannot be converted to lvalues. The following is fine

int x = 1;     // x is an lvalue
int y = 2;     // y is an lvalue
int z = x + y; // the "+" needs rvalues, so x and y are converted to rvalues 
               //(from lvalues) and an rvalue is returned

Now if I do

x = 5;
y = 6;

Aren't x and y converted to lvalues (from rvalues)?

Edit: The question in What are rvalues, lvalues, xvalues, glvalues, and prvalues? has little to no reference to conversion and no examples to explain.

ontherocks
  • 1,747
  • 5
  • 26
  • 43
  • No, they're being assigned to from an rvalue. – Steve Oct 31 '17 at 16:58
  • 2
    Possible duplicate of [What are rvalues, lvalues, xvalues, glvalues, and prvalues?](https://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues) – Caleth Oct 31 '17 at 17:06
  • In `x + y`, the objects denoted by `x` and `y` are **copied** into the actual parameters of the function `int operator+(int, int)`. "x and y are converted to rvalues" is not true – Caleth Oct 31 '17 at 17:09
  • @Caleth the place where I came across this is https://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c – ontherocks Oct 31 '17 at 17:32
  • 1
    `x` and `y` don't *change*. The *expression* `x` is always a lvalue expression of type `int`. The *value* of `x` is used, in an rvalue context – Caleth Oct 31 '17 at 18:25

2 Answers2

3

It's important to be precise about what we're talking about.

  • In C++, an expression has a type, and can be either an lvalue or rvalue (value category)
  • An implicit conversion occurs when an expression of one (type, value category) occurs in a context where a different (type, value category) is expected.
  • An explicit conversion uses one of the language's cast operators, taking a subexpression of one (type, value category) as an operand, and yielding an expression of a different (type, value category) as the result.

An lvalue or xvalue can be implicitly converted to a prvalue; this is called the lvalue-to-rvalue conversion for historical reasons. The line

int z = x + y;

serves as an example of this implicit conversion. As the comment explains, the built-in + operator expects prvalues as its operands but we have supplied lvalues instead, so an implicit conversion occurs.

An lvalue can also be explicitly converted to an xvalue:

std::string s1 = static_cast<std::string&&>(s2);  // i.e., std::move(s2)

Here s2 is an lvalue but we want to make sure the initializer is an xvalue so that the move constructor will be used, so we perform an explicit conversion.

An rvalue can be neither implicitly nor explicitly converted to an lvalue. For example, the following does not compile:

3++;

because the ++ operator requires an lvalue, and we have supplied an rvalue. Nor will the following compile, where we attempt to explicitly convert an rvalue to an lvalue:

static_cast<int&>(3)++;

(Note: the type of 3 is int, not const int. Constness is not the reason why we cannot modify 3.)

There is actually no conversion occurring in the assignments shown:

x = 5;
y = 6;

because when assigning to an int lvalue, a prvalue is expected as the right-hand operand, and a prvalue has been supplied. Although we are doing some sort of operation that has an rvalue as the source and an lvalue as the destination, this is not a conversion according to the rules of the language.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 1
    +1 for this answer, but it's not quite right that "An rvalue can be neither implicitly nor explicitly converted to an lvalue". Consider a class `Foo` (with a default constructor). Then, `auto foo = static_cast(Foo())` is indeed an explicit rvalue-to-lvalue conversion. This will invoke the copy constructor of `Foo`. Also consider the example of `unmove()` in this post: https://stackoverflow.com/questions/44677825/rvalue-to-lvalue-conversion – niran90 Jul 10 '22 at 07:48
-1

Lvalue kinda means "address". Rvalue kinda means "value". An expression is either an lvalue or an rvalue. As an expression x is an lvalue, however, in the expression z = x + y; the + operator needs data, so x and y are dereferenced. That is, the value at their addresses are fetched, and it is these rvalue values that are added together, producing an rvalue equal to their sum. The assignment operator needs an lvalue on the left and an rvalue on the right. It puts the value on the right into the address on the left, so z is not dereferenced, and is an lvalue.

A variable like x can't be said to be either an lvalue or an rvalue until you know its context.

seattlecpp
  • 177
  • 1
  • 7
  • the *expression* `x` is **always** an lvalue. the *statement* `int x;` defines `x` as an object of type int, and the *statement* `int x = 1;` defines `x` and initialises it. – Caleth Oct 31 '17 at 18:18
  • IMO it is confusing to use pointer terminology when we are not talking about pointers. Also `x` is definitely an lvalue regardless of context. – M.M Nov 01 '17 at 23:59