Incrementing rvalue in C++

145 Views Asked by At

Does anyone know why this code does not compile

int main() {
  int i = 7;
  int j = ++i++; // error: lvalue required as increment operand
}

while this code compiles perfectly?

int main() {
  Int i{7};
  Int j = ++i++; // OK!
}

The class Int is defined as follows:

struct Int {
  int i;
  Int(int i = 0) : i{i} {}
  Int& operator++() {++i; return *this;}
  Int operator++(int) {Int t{*this}; ++i; return t;}
};

When I compile the first code snippet it fails with error "lvalue required as increment operand." The other one compiles and works as expected.

1

There are 1 best solutions below

4
doug On

It comes down to the differences between xvalues and prvalues. Both are rvalues but an xvalue is also a glvalue which means one can take it's address, assign to it, and otherwise operate on it. Class types, but not native types, will convert a prvalue to an xvalue when needed.

Let's start by looking at:

int i = 7;
int j = ++i++; // error: lvalue required as increment operand

Since i++ has higher precedence than ++i the last line can be re-written:

int j = ++(i++);

While i is an lvalue, i++ is a prvalue. In this example it has a value of 7 while i is now 8. ++8 is invalid since you can't increment, decrement, or assign to a prvalue.

Now let's look at:

struct Int {
    int i;
    Int(int i = 0) : i{ i } {}
    Int& operator++() { ++i; return *this; }
    Int operator++(int) { Int t{ *this }; ++i; return t; }
};
int main() {
    Int i{ 7 };
    Int j = ++i++; // OK!
}

Here, i++ returns an prvalue which is then converted to an xvalue through temporary materialization. It is temporarily materialized so the pre ++ operator can now operate on it thus setting the temporary object's value to 8 and assigning it to j.