Rvalue reference or lvalue?
Asked Answered
I

2

12

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 ?

Iotacism answered 27/9, 2020 at 13:25 Comment(0)
K
11

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.

Kymberlykymograph answered 27/9, 2020 at 13:33 Comment(11)
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<int&&>(3) is int rather than int &&.Resile
for anyone wanting to know more: a decent read: en.cppreference.com/w/cpp/language/value_categoryTatum
@Resile Ok, reworded a fair bit. Should be clear now.Kymberlykymograph
@Kymberlykymograph 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.Resile
@Kymberlykymograph I'm slightly confused with "it doesn't have a name so it's rvalue" argument. Why does (static_cast<int&>(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<int&> and static_cast<int&&> ? Both return reference, right ? To sum up, why does expression static_cast<int&> have a name ?Iotacism
@domocar1 No, (static_cast<int&&>(k))++; returns a r-value reference, which is not modifiable, whereas (static_cast<int&>(k))++; returns an l-value reference, which is modifiable. static_cast<int&> casts to an l-value reference.Kymberlykymograph
@Kymberlykymograph 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.Iotacism
@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.Kymberlykymograph
@Kymberlykymograph Yeah, I get that part. The part I don't get; how do I know that static_cast<int&&>(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<int&>(k) has a name ?Iotacism
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 will help.Kymberlykymograph
Let us continue this discussion in chat.Iotacism
I
0

Because rvalue reference variable is lvalue

According to cppreference

lvalue Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression (but see Move-eligible expressions);

Isoagglutination answered 5/9, 2023 at 4:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.