10

I've got a question of similiar nature like this one posted 5 years ago: Why are rvalues references variables not rvalue?

My major concern is why can I do this:

int&& k = 3;
k++;

but I cannot do this:

(static_cast<int&&>(3))++;

I've always interpreted rvalue references as lvalues since rvalue reference variables are lvalues. But apparently that is not the case. Can someone explain to me why the (static_cast<int&&>(3))++; results in using rvalue as lvalue ?

domdrag
  • 541
  • 1
  • 4
  • 13

1 Answers1

10

The confusion is probably arising from the difference between r-value and r-value reference. The former is a value-category which only applies to expressions, while the latter is a type which applies to variables (technically it would need to be an r-value reference of some type, e.g. r-value reference to int).

So the difference between the snippets you've shown is not actually related to the type of the variable, but the value-category of the expression. Postfix operator++ requires the value-category of the operand to be an l-value, regardless of the type of the operand.

In k++, the expression k is an l-value (roughly speaking, it has a name), which is its value-category. The type of the variable k is an r-value reference, but that's fine.

In (static_cast<int&&>(3))++, the expression static_cast<int&&>(3) is an r-value (it doesn't have a name), which is its value-category. Regardless of the type of static_cast<int&&> (which is int), the value-category is wrong, and so you get an error.

Note that the error message using rvalue as lvalue is referring to the value-category of the expression being used. It has nothing to do with the types of the variables.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • 4
    I think it's important to note that expressions can't have reference types. The type of **variable** `k` is `int &&`, but the type of the **expression** `k` is just `int` (and that expression is an lvalue). This also means that the type of `static_cast(3)` is `int` rather than `int &&`. – HolyBlackCat Sep 27 '20 at 13:36
  • for anyone wanting to know more: a decent read: https://en.cppreference.com/w/cpp/language/value_category – bolov Sep 27 '20 at 13:43
  • @HolyBlackCat Ok, reworded a fair bit. Should be clear now. – cigien Sep 27 '20 at 13:49
  • 2
    @cigien Looks good. I'll leave my comment there, since the "expressions can't have reference types" is what made it click for me when I was first learning it. – HolyBlackCat Sep 27 '20 at 13:53
  • @cigien I'm slightly confused with "it doesn't have a name so it's rvalue" argument. Why does `(static_cast(k))++` work where `k` is some int variable ? I get that that expression returns reference to k and reference is defined as another name for an object, but then what is the difference between `static_cast` and `static_cast` ? Both return reference, right ? To sum up, why does expression `static_cast` have a name ? – domdrag Sep 28 '20 at 12:20
  • @domocar1 No, `(static_cast(k))++;` returns a r-value reference, which is not modifiable, whereas `(static_cast(k))++;` returns an l-value reference, which is modifiable. `static_cast` casts to an l-value reference. – cigien Sep 28 '20 at 12:23
  • @cigien I'm sorry, I'm even more confused now. Rvalue reference is not modifiable ? Did you mean in general or just in this case ? Because, `int&& k=3; k++;` works. – domdrag Sep 28 '20 at 12:26
  • @domocar1 Again, as I said in the answer, the difference is the *type* vs the *value-category*. In `int&& k=3;`, `k` is of type `r-value reference`, but the value-category is `l-value`. Whether an expression can be modified or not depends on the value-category, not the type. – cigien Sep 28 '20 at 12:30
  • @cigien Yeah, I get that part. The part I don't get; how do I know that `static_cast(3)` is rvalue ? You stated that the reason is that it doesn't have a name. And that makes sense also. But then what does not makes sense to me is why does the expression `static_cast(k)` has a name ? – domdrag Sep 28 '20 at 12:34
  • I'm sorry about the usage of "has a name". I wrote "roughly speaking ..." in the paragraph above because it's not *exactly* correct. The value-category of an expression is more specific than that (it's whether the expression can be *used* as an l-value). Perhaps this [demo](https://godbolt.org/z/q9rToG) will help. – cigien Sep 28 '20 at 12:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222177/discussion-between-domocar1-and-cigien). – domdrag Sep 28 '20 at 12:48