why can an xvalue be an glvalue or a rvalue in C++17?

an xvalue is an expiring rvalue at the right side of an assignment.
in which circumstance is an xvalue a glvalue? can we place an xvalue on the left side of an assignment?

Also, why is a string literal an lvalue??

Why are temporaries prvalues - shouldn't they be eXpiring values (xvalues)?
Last edited on
This may help, especially the diagram near the end:

https://www.stroustrup.com/terminology.pdf

But mainly, it is all explained here:

https://en.cppreference.com/w/cpp/language/value_category

I think the statements in your question are reversed, which leads to the confusion. A rvalue is either an xvalue or a prvalue; a glvalue is either an xvalue or an lvalue; temporaries are xvalues.

Also, why is a string literal an lvalue??


A simple search reveals:
https://stackoverflow.com/questions/10004511/why-are-string-literals-l-value-while-all-other-literals-are-r-value
I'm not an expert on the value categories but I'll try...

Please don't trust what I say blindly and correct me if I'm wrong. Maybe I learn something in the process.

in which circumstance is an xvalue a glvalue?

Always.

can we place an xvalue on the left side of an assignment?

I don't think so. The docs seem to say it has to be an lvalue.

Also, why is a string literal an lvalue??

Perhaps because it gives you a static object that stays alive for the rest of the program. Using the same literal multiple times normally give you the same object each time. Two identical string literals in different parts of the code might even give you the same object. This is quite different from other type of literals.

Why are temporaries prvalues - shouldn't they be eXpiring values (xvalues)?

I have to admit that thinking about this makes my head spin, but I found this:
- Value categories describe expressions, not objects.
- "Temporary materialization" (which I think is what creates the temporary) involves a prvalue being converted into a xvalue.
So to me it seems like the original expression is probably a prvalue but it is implicitly converted into an xvalue when the temporary is materialized/created... Something like that maybe?
juandent wrote:
in which circumstance is an xvalue a glvalue?


Peter87 wrote:
Always.


But an xvalue could be an rvalue. So maybe an xvalue is a glvalue when it is not an rvalue?

Edit:
juandent wrote:
can we place an xvalue on the left side of an assignment?
Peter87 wrote:
I don't think so. The docs seem to say it has to be an lvalue.

But something can be an xvlaue because it goes out of scope at the end of a function, so one can assign to it at that point.
Last edited on
TheIdeasMan wrote:
But an xvalue could be an rvalue. So maybe an xvalue is a glvalue when it is not an rvalue?

Am I reading it wrong?

        expression
          /    \
         /      \
     glvalue   rvalue
      /   \    /   \
     /     \  /     \
lvalue    xvalue    prvalue 
https://eel.is/c++draft/basic.lval#fig:basic.lval

I thought this meant that
an lvalue is a glvalue,
an xvalue is both a glvalue and an rvalue,
a prvalue is an rvalue,
and that all of them are expressions.
can we place an xvalue on the left side of an assignment?

Yes, a contrived example:
std::move(x) = y;

An xvalue has identity and can be moved from.

std::move(x) can, unsurprisingly, be moved-from.
std::move(x) also has identity, because move returns a reference type, and that reference refers to an object with identity. All objects have identity.

| Value category | Fundamental? | Has identity?  | Can be moved from? |
|----------------+--------------+----------------+--------------------|
| lvalue         | yes          | yes            | no                 |
| xvalue         | yes          | yes            | yes                |
| prvalue        | yes          | no             | yes                |
|----------------+--------------+----------------+--------------------|
| glvalue        | no           | yes            | doesn't matter     |
| rvalue         | no           | doesn't matter | yes                |


Why are temporaries prvalues - shouldn't they be eXpiring values (xvalues)?

It doesn't make sense to talk about the value category of an object, whether that object is temporary or otherwise. Objects don't have a value category.
Last edited on
Peter87 wrote:
Am I reading it wrong?


In the cppreference, I observe they use the word "either" rather than "and".

mbozzi's table also ties in with the Stroustrup article I linked earlier, where identity and movable were part of the notation, which eventually lead to the naming of the value categories.
TheIdeasMan wrote:
In the cppreference, I observe they use the word "either" rather than "and".

Yes, but they talk about glvalues and rvalues.

cppreference wrote:
A glvalue expression is either lvalue or xvalue.
An rvalue expression is either prvalue or xvalue.

This is not incompatible with what I said about xvalues being both glvalues and rvalues.

Note that the standard shows the lines as arrows so it's not the same relationship in both directions.

Here is the same structure, but involving animals instead of expressions, which might help illustrate how I think the tree works:

          animal
          /    \
         /      \
     mammal   aquatic
      /   \    /   \
     /     \  /     \
elephant   whale    shark

A whale is both aquatic and it is a mammal. It is not just one or the other.

TheIdeasMan wrote:
mbozzi's table also ties in with the Stroustrup article I linked earlier, where identity and movable were part of the notation, which eventually lead to the naming of the value categories.

I had not read Stroustrup's article before. I did and now it's much clearer. Now I'm even more convinced that I'm right about all xvalues being both glvalues and rvalues. What mbozzi wrote does not go against this.

I found the following quote, on the naming of xvalues, interesting:
Stroustrup wrote:
They are important to people working with the (draft) standard text, but are unlikely to become a household name. We didn’t find any real constraints on the naming to guide us, so we picked ‘x’ for the center, the unknown, the strange, the xpert only, or even x-rated.

This strengthens the feeling I have that most programmers don't need to have a good understanding of the value categories (except an informal idea of what "lvalues" and "rvalues" are). It's often enough to think that T() creates a temporary, and if it doesn't we just think of it as (guaranteed) "copy ellision" even though it's not exactly how the standard explains it. I know I can move from a non-const variable by using std::move, I don't need to know what value category that expression has.

If you think I'm wrong, and that I will benefit a lot in my day-to-day programming from having a solid understanding on how the value categories work and interact with each other in different contexts, then please tell me. I'm obviously biased and I know it's hard to see the benefit of something before learning it properly.
Last edited on
JUANDENT wrote:
can we place an xvalue on the left side of an assignment?
Peter87 wrote:
I don't think so. The docs seem to say it has to be an lvalue.
TheIdeasMan wrote:
But something can be an xvlaue because it goes out of scope at the end of a function, so one can assign to it at that point.
mbozzi wrote:
Yes, a contrived example:
std::move(x) = y;

There seems to be a difference between the built-in assignment operator and assignment operators for class types.

1
2
3
4
5
6
7
8
5 = 10; // ERROR: can't assign to a prvalue 
        // GCC says `error: lvalue required as left operand of assignment`

int x = 5;
std::move(x) = 10; // ERROR: can't assign to an xvalue 
                   // GCC says `error: using xvalue (rvalue reference) as lvalue`

x = 10; // OK: assigning to an lvalue is allowed 


1
2
3
4
5
6
std::string("A") = std::string("B"); // OK

std::string s("A");
std::move(s) = std::string("B"); // OK

s = std::string("B"); // OK 


I think it's allowed for classes because the assignment operator is technically a member function and you are allowed to call member functions on rvalues (i.e. xvalues and prvalues).
Last edited on
Well the whole thing is confusing .... and I could easily be wrong, wait I am wrong :+)

Maybe I was confused by the diagram in the Stroustrup paper being upside down compared to the one in the standard and lacking arrows, and I hadn't seen the one in the standard.

Anyway, I hope you are all looking forward to a great holiday season - cheers :+D



There seems to be a difference between the built-in assignment operator and assignment operators for class types.

The standard draft says
The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand; their result is an lvalue of the type of the left operand, referring to the left operand.
So it seems you're right that an xvalue can't go on the left of the built-in assignment operator.
https://eel.is/c++draft/expr.ass#1.sentence-2

Anyway, I hope you are all looking forward to a great holiday season - cheers :+D

Happy holidays! :)
Last edited on
Topic archived. No new replies allowed.