4

So I read this answer because I was confused about when values are considered as xvalue, like when a value is expiring/near the end of its lifetime. The sad thing is that I am still very confused.

Anyway, the quotation included this:

  • a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

  • a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

There was also an example included in the answer but it did not exemplify(I guess) "a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.", so could anyone please show me one?

However, it does exemplify "a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue" when doing f().m and the fact that m is an xvalue/an rvalue about to end makes sense to me since the f() returns an rvalue reference. But a is an lvalue, so what if you did a.m, isn't that still an lvalue?

The confusion thing here is that this member access expression is still designating a non-static data member of non-reference type.. Or when saying "in which the object expression is an xvalue", does it mean that the class object has to be an rvalue?

The example mentioned in the answer:

struct A {
    int m;
};

A&& operator+(A, A);
A&& f();
A a;
A&& ar = static_cast<A&&>(a);

2 Answers2

2

a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue

A "class member access expression" (that is, an expression of the form A.B) consists of two parts, an object expression (the part before the ., the A) and the member identification (the part after the ., the B).

Therefore, this paragraph applies only when the part before the . is an xvalue.

An example involving .* is very similar to one involving just .:

struct A {
    int m;
};
int A::* p = &A::m;
A&& f();

std::cout << f().*p;

The expression f().*p is an xvalue.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Thanks bud :) So just to confirm, the object expression has to be an xvalue in order for the whole class member access expression will be evaluated to an xvalue, right? In that case, does xvalue mean an rvalue? I have read about xvalues though but they all look like rvalues to me. –  Jun 27 '17 at 13:21
  • @noflow xvalues are rvalues – Marco A. Jun 27 '17 at 13:22
  • @noflow rvalues come in two subcategories, prvalues and xvalues. xvalues are *also* glvalues (which are lvalues and xvalues) – Caleth Jun 27 '17 at 13:24
  • @MarcoA. if you take a look at when an expression is an xvalue from the linked answer, isn't an rvalue always an xvalue then? Or are they only rvalues in given scenarios, like those mentioned in the quotation=? –  Jun 27 '17 at 13:29
  • 1
    @noflow from the examples you've posted, as stated, they're all *xvalues* (and also *rvalues*). A *rvalue* can also be a *prvalue* and therefore **not** an *xvalue* (e.g. a function returning a non-reference object by value.. you can't directly and immediately access that object's properties - the so-called identity - unless you copy/initialize something with it). – Marco A. Jun 27 '17 at 13:39
  • @noflow The bottom-most, disjoint categories are lvalue, xvalue, prvalue. The middle tier is above them; lvalues and xvalues together are called glvalues, xvalues and prvalues together are called rvalues. The top tier is just one term: value, encompassing both glvalues and rvalues. Does that clarify? – Angew is no longer proud of SO Jun 27 '17 at 15:10
  • 1
    @noflow Rough rule of thumb: lvalue = named object, dynamic object, lvalue reference. xvalue = unnamed rvalue reference. prvalue = unnamed non-reference object. – Angew is no longer proud of SO Jun 27 '17 at 15:11
  • @Angew cool, that is really helpful. I had just always thought that a xvalue was related to both rvalues and lvalues since in one chart it shows an arrow from both glvalues and rvalues to xvalues and since lvalues are included as glvalues. I mean xvalues are related to rvalues since they a references to rvalues but they not related to lvalues which still is a little odd to me since that arrow from glvalues to xvalues? –  Jun 27 '17 at 15:37
  • @noflow An xvalue is both a glvalue and an rvalue. It's not an lvalue. – Angew is no longer proud of SO Jun 27 '17 at 15:40
  • But a glvalue is both a lvalue and an xvalue, so how can an xvalue not be an lvalue too if it is a glvalue? @Angew –  Jun 27 '17 at 16:10
  • 1
    @noflow No. Each particular glvalue is *either* an lvalue *or* an xvalue. It can never be both. Every lvalue is a glvalue, but not necessarily vice versa. Every xvalue is a glvalue, but not necessarily vice versa. – Angew is no longer proud of SO Jun 27 '17 at 16:36
1

There was also an example included in the answer but it did not exemplify(I guess) "a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.", so could anyone please show me one?

Here's an example:

struct C { int m = 42; };

int C::* p = &C::m;
C&& get_xvalue();

std::cout << get_xvalue().*p; // get_xvalue() is an xvalue, p is a pointer to member

a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue

This means that accessing non-static data member of non-reference type can have lvalue or xvalue value category depending on the value category of the object expression (i.e. of the part before the dot .). It will always be lvalue regardless, if the data member it is of reference type.

E.g.

struct C {
  std::string x;
};

C obj;
std::move(obj.x) // rvalue and xvalue expression
std::move(obj).x // In this case xvalue since `x` is not a reference type. Otherwise it would have been lvalue
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Thanks! But based on the statement of when an expression is an xvalue, I do not see lvalue being mentioned anywhere, so how can xvalues be associated with lvalues? I do see how they can be associated with rvalues since rvalue references are near the end of their lifetime(i.e. xvalues, please correct me again if I am wrong) which you helped me understand. –  Jun 27 '17 at 14:04
  • 1
    @noflow [here's an example](https://www.reddit.com/r/cpp/comments/5opa8c/howard_hinnant_everything_you_ever_wanted_to_know/dcm8pfu/) of this last concept - they're not *associated*, the rule might prevent the expression from being an *xvalue*, that's all – Marco A. Jun 27 '17 at 14:06
  • Hmm but how can you say xvalues and lvalues are not associated if xvalues are rvalues and glvalues when glvalues includes lvalues? –  Jun 27 '17 at 14:09
  • Hold on, I think you misunderstood what I was talking about... I was talking about the linked answer where it included the quoutation about when an expression is an xvalue and that I did not see lvalue being mentioned anywhere, so how can xvalues be associated with lvalues then and not just rvalues? –  Jun 27 '17 at 14:15
  • @noflow The chart still holds, since we were talking about xvalue expressions [this paragraph](http://eel.is/c++draft/expr#5) is relevant and might help to clear out some more doubts – Marco A. Jun 27 '17 at 14:18
  • Thanks for the link, but I still do not really get and man it is quiet frustrating... The chart shows that an xvalue is both rvalues and glvalues(i.e. also lvalues), why are lvalues and xvalues distinguished? Like in the paragraph you linked "the expression is an lvalue or an xvalue". Sorry for taking much of your time. –  Jun 27 '17 at 14:36
  • @noflow because you can **move** from an *xvalue*, you **cannot move** from an *lvalue*. [Here's a rough sketch](http://i.imgur.com/Vgad61w.png) – Marco A. Jun 27 '17 at 14:38
  • Okay, so the conclusion is that xvalues and lvalues are not the same, like xvalues and rvalues are? Or am I really just mixing things up? –  Jun 27 '17 at 14:39
  • @noflow they're not the same, look at the chart you posted. *A glvalue (“generalized” lvalue) is an lvalue or an xvalue*. *An rvalue is an xvalue, a temporary object or subobject thereof, or a value that is not associated with an object* (prvalue, ndMarco) – Marco A. Jun 27 '17 at 14:47
  • Great, I actually think that I got it. Uhh that was a tough one, thank you so much! –  Jun 27 '17 at 14:50