How to test lvalue or rvalue in this case - c++

The code is as following:
struct A
{
static int k;
  int i;
};
 
int A::k = 10;
 
A func() { A a; return a; }
My question is, how can I tell whether func().k or func().i is an lvalue or not? If both are lvalues/rvalues, how can I test them?
func().k = 0; // compile ok under g++-4.4 and g++-4.6
func().i = 1; // compile ok with g++-4.4, but g++-4.4 gives an error:
//"using temporary as lvalue [-fpermissive]"

func().k is an lvalue and func().i is an xvalue.
You can see this for more details:
rvalues and temporary objects in the FCD
Althrough, it is not difficult to test whether they are lvalues or rvalues:
#include <iostream>
struct A
{
static int k;
int i;
};
int A::k = 10;
A func( ){ A a; return a; }
void f (int & ) { std::cout << "int& " << std::endl; }
int main ()
{
func().k = 0; //ok, because func().k is an r
f(func().k);
func().i = 1; //compile error: "using temporary as lvalue"
f(func().i); //compile error because func().i is an rvalue of type ‘int’
return 0;
}

"Assignability" isn't a good test for lvalueness as we can have non-mutable lvalues (e.g. const reference expressions) and assignment may be a member function call which can be made on an rvalue of class type.
You have to refer to the standard (ISO/IEC 14882:2011).
5.2.2/10: A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
So func() is a prvalue.
5.2.5/4: If E2 is declared to have type "reference to T," then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise, one of the following rules applies.
If E2 is a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates the named member of the class. The type of E1.E2 is T`.
So func().k is an lvalue.
If E2 is a non-static data member and the type of E1 is "cq1 vq1 X", and the type of E2 is "cq2 vq2 T", the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; otherwise, it is a prvalue. [...]
So func().i is a prvalue.

There is no need to actually "test" whether a given value is an lvalue or an rvalue.
Etymologically/Historically, an lvalue is what is on the left side of the assigment operator, and an rvalue what is on the right side. (This definition is not exactly correct though.) Note that rvalues can be lvalues.
Simple rule of thumb: If you can take its address, it's an lvalue. However, in C++11 there are rvalue references which makes things not that simple. So the rule is more like: if you can take its address using &.
Maybe some examples will clear things up:
int a = 5; // a is an lvalue, 5 is an rvalue
int b = fun(); // fun is an rvalue
fun() = a; // illegal, can't assign to an rvalue (suppose foo returns int)
See http://en.wikipedia.org/wiki/Value_%28computer_science%29 for more.

I am not sure what exactly you are trying to achieve but as you are allocating memory within scope of function() returning that object. This object goes out of scope once the call to function() returns and hence it can be freed by the compiler. You can face a lot of troubles in later phases. I think you need to redesign the problem solution.

Related

Can a member function returns a modifiable lvalue reference to an rvalue object?

I have a bit confusion about this code:
struct A
{
A& bar()&&;
};
A& A::bar()&&
{
std::cout << "A::bar()&&\n";
return *this;
}
int main()
{
A{}.bar();// called by an rvalue
}
So what I understand is that bar can be called only by a modifiable-rvalue. Until this it is OK. But how can bar return a non-constant lvalue reference to that rvalue?
How bar() binds and returns a modifiable lvalue reference to that rvalue object?
The reason is that the this pointer for a class C can be either C* or const C* - not C& * or C&& * (those aren't actual types; you can't declare a C& * ptr). So, even when your method runs for an rvalue instance of class A, you get one of those two (GodBolt). And when you apply the * operator, you get an lvalue, not an rvalue.
This has to do with [expr.unary.op]/1
The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T”, the type of the result is “T”. [ Note: Indirection through a pointer to an incomplete type (other than cv void) is valid. The lvalue thus obtained can be used in limited ways (to initialize a reference, for example); this lvalue must not be converted to a prvalue, see [conv.lval]. — end note ]
emphasis mine
So when you dereference this yo get an lvalue. It doesn't matter if this is pointing to a temporary object or not, you will always get an lvalue. Since *this is an lvalue, you are legally allowed to return an lvalue reference, the program in syntactically correct. Semantically it is not, but that is a lot harder to test for and is often not something that is diagnosed as it requires quite a bit of static analysis.
It would be cool if the language could be updated where * only yields an lvalue when applied to this in a non-rvalue qualified function.

Returning a member from an rvalue object

Lets take two structs/classes
struct C1{
C1(){};
C1(C1&){std::cout<<"copy"<<std::endl;}
C1(C1&&){std::cout<<"move"<<std::endl;}};
struct C2{
C1 c;
C2(){};
C1 get1(){return c;}
C1 get2(){return std::move(c);}};
And than
C1 a1=C2().c;
C1 a2=C2().get1();
C1 a3=C2().get2();
the output is
move
copy
move
Question
We know that members of rvalues are rvalues themselves. This is why with a1, the move constructor is called. Why than, is the copy constructor called in the case of a2. We are returning an rvalue from a function.
To put it differently, std::move casts to an rvalue. But, as a member of an rvalue, c, is already an rvalue. Why than is there a difference between the behavior with a2 and a3?
Good question. The dull answer is that there's just no no rule in the C++ spec that says that returning a member from a dying object like this automatically moves it.
You may be interested in what's called rvalue reference to this. It let's you overload on && and & such that you can manually implement the behaviour you expected:
struct C2{
C1 c;
C2(){};
C1 get1() & { std::cout << "&" << std::endl; return c;}
C1 get1() && { std::cout << "&&" << std::endl; return std::move(c);}
C1 get2(){return std::move(c);}
};
Now
C1 a2=C2().get1();
prints
&&
move
Cool, but quite rare.
Related:
What is "rvalue reference for *this"?
Is a member of an rvalue structure an rvalue or lvalue?
We know that members of rvalues are rvalues themselves.
Yes this is true, as states [expr.ref]/4.2 (emphasis mine):
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
And also, from [expr.ref]/4.5:
If E2 is a member enumerator and the type of E2 is T, the expression E1.E2 is a prvalue. The type of E1.E2 is T.
So far so good. You can only get an lvalue if E1 is an lvalue itself, otherwise it's an xvalue or a prvalue.
But, as a member of an rvalue, c, is already an rvalue.
This is where your assumptions are wrong.
From [class.this]/1 (emphasis mine)
In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value
is the address of the object for which the function is called. The type of this in a member function of
a class X is X*.
this is a prvalue of type X*, and dereferencing a pointer of type X yield an lvalue of type X.
Since accessing a member inside a member function is equivalent to (*this).m, then m is accessed through an lvalue of type X.
So your code is equivalent to:
C1 get1() { return (*this).c; }
// lvalue ----^ ^--- must be an lvalue too then.
Since this is always the same type, then even when using a function ref-qualifier the expression c inside a member function will always be an lvalue:
C1 get1() && { return (*this).c; }
// ^---- lvalue again, accessing through a pointer

Is reference itself a lvalue?

I saw an answer about lvalue yesterday, what below is its content:
— An lvalue (so called, historically, because lvalues could appear on
the left-hand side of an assignment expression) designates a function
or an object. [ Example: If E is an expression of pointer type, then
*E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function
whose return type is an lvalue reference is an lvalue. —end example ]
so a question comes out: is reference itself a lvalue?
I know that both lvalue-reference and rvalue-reference can appear on the left-hand side of an assignment expression, but reference is neither function nor object, is there a contradiction? And Is reference really a lvalue?
Moreover, if a reference is a lvalue, what's the type of decltype(reference-expression), for example:
int main (void) { int a = 1; int &b = a; decltype((b)) c; }
what's the type of c?
In your code, the expression b is an lvalue, with type int.
The declaration of c is the same as int &c. (So it's ill-formed since you didn't provide an initializer). If you did provide an initializer, the expression c is an lvalue with type int.

I'm having some difficulty interpreting bullet point (5.2.1.1) in paragraph §8.5.3/5 of N4140

The snippet below compiles
#include <iostream>
int& f() { static int i = 100; std::cout << i << '\n'; return i; }
int main()
{
int& r = f();
r = 101;
f();
}
and print the values (live example)
100
101
Now, reading §8.5.3/5 in N4140, I can see that it compiles because of bullet point (5.1.1), that is, the reference is an lvalue reference, the initializer expression is an lvalue and int is reference-compatible with int (or with int& - I don't know for sure which one I should use here).
Bullet points (5.1) and (5.1.1):
— If the reference is an lvalue reference and the initializer expression
— is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with
“cv2 T2,” or ...
Now suppose I change the left value reference in the declaration int& r = f(); by a right value reference, i.e., int&& r = f();. I know the code won't compile, as an rvalue reference doesn't bind to an lvalue. But what I'm curious is, how to reach this conclusion using the Standard?
I'll explain what are my difficulties:
Clearly int&& r = f(); is covered by bullet point (5.2), because the reference is an rvalue reference.
Bullet point (5.2):
— Otherwise, the reference shall be an lvalue reference to a
non-volatile const type (i.e., cv1 shall be const), or the reference
shall be an rvalue reference.
In principle, I would say that (5.2.1.1) supports this initialization as the initializer is a function lvalue and int is reference compatible with int (or with int&).
Bullet points (5.2.1) and (5.2.1.1):
— If the initializer expression
— is an xvalue (but not a bit-field), class prvalue, array prvalue or function
lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or ...
Edit
I've included the bullet points verbatim from N4140 (C++14), which are equivalent to similar bullet points in N3337 (C++11).
the initializer expression is an lvalue and int is reference-compatible with int (or with int& - I don't know for sure which one I should use here).
Reference-compatibility is a relation applied to the type referred to, not the reference type. For example, [dcl.init.ref]/5 talks about intializing "a reference to type cv1 T1 by an expression of type cv2 T2", and later compares e.g. "where T1 is not reference-related to T2".
The type of the expression f() is just int, despite the fact that the return type of f is int&. Expressions simply do not have reference type when we observe them(*); the reference is stripped and used to determine the value category (see [expr]/5). For int& f(), the expression f() is an lvalue; for int g(), the expression g() is an rvalue.
(*)To be perfectly precise, expressions can have reference type in the Standard, but only as the "initial" resulting type. The reference is dropped "prior to any further analysis", which implies that this referencess is simply not observable through the type.
Now suppose I change the left value reference in the declaration int& r = f(); by a right value reference, i.e., int&& r = f();. I know the code won't compile, as an rvalue reference doesn't bind to an lvalue. But what I'm curious is, how to reach this conclusion using the Standard?
The confusion, as it seems from the discussion in the comments, seems to be that f() is not a function lvalue. Value categories such as "lvalue" and "rvalue" are properties of expressions. The term "function lvalue" must therefore refer to an expression, namely an expression of function type with the value category "lvalue".
But the expression f() is a function call expression. Grammatically, it's a postfix-expression, the postfix being the function argument list. As per [expr.call]/10:
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
And [expr.call]/3
If the postfix-expression designates a destructor [...]; otherwise, the type of the function call expression is the return type of the statically chosen function [...]
That is, the (observed see above) type of the expression f() is int, and the value category is "lvalue". Note that the (observed) type is not int&.
A function lvalue is for example an id-expression like f, the result of indirecting a function pointer, or an expression yielding any kind of reference to function:
using ft = void();
void f();
ft& l();
ft&& r();
ft* p();
// function lvalue expressions:
f
l()
r()
*p()
[expr.prim.general]/8 specifies that those identifiers like f are, as id-expressions, lvalues:
An identifier is an id-expression provided it has been suitably declared. [...] The type of the expression is the type of the identifier. The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise.
Back to the example int&& r = f();. Using some post-N4296 draft.
[dcl.init.ref]
5 A reference to type “cv1 T1” is initialized by an expression of type
“cv2 T2” as follows:
(5.1) If the reference is an lvalue reference and the initializer expression
The reference is an rvalue reference. 5.1 does not apply.
(5.2) Otherwise, the reference shall be an lvalue reference to a
non-volatile const type (i.e., cv1 shall be const), or the reference
shall be an rvalue reference. [example omitted]
This applies, the reference is an rvalue-reference.
(5.2.1) If the initializer expression
(5.2.1.1) is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and [...], or
(5.2.1.2) has a class type (i.e., T2 is a class type) [...]
The initializer is an lvalue of type int. 5.2.1 does not apply.
(5.2.2) Otherwise:
(5.2.2.1) If T1 or T2 is a class type [...]
(5.2.2.2) Otherwise, a temporary of type “cv1 T1” is created and copy-initialized (dcl.init) from the initializer expression. The reference is then bound to the temporary.
Finally, 5.2.2.2 applies. However:
If T1 is reference-related to T2:
(5.2.2.3) cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2; and
(5.2.2.4) if the reference is an rvalue reference, the initializer expression shall not be an lvalue.
T1 and T2 are int (the reference of the return type of f() is removed and used only to determine the value category), so they're reference-related. cv1 and cv2 are both empty. The reference is an rvalue reference, and f() is an lvalue, hence 5.2.2.4 renders the program ill-formed.
The reason why the term "function lvalue" appears in 5.2.1.1 might be related to the problem of "function rvalues" (see, for example, N3010 - Rvalue References as "Funny" Lvalues). There were no function rvalues in C++03, and it seems the committee didn't want to introduce them in C++11. Without rvalue references, I think it's impossible to get a function rvalue. For example, you may not cast to a function type, and you may not return function types from a function.
Probably for consistency, function lvalues can be bound to rvalue references to function types via a cast:
template<typename T>
void move_and_do(T& t)
{
T&& r = static_cast<T&&>(t); // as if moved
}
int i = 42;
move_and_do(i);
move_and_do(f);
But for T being a function type like void(), the value category of static_cast<T&&>(t) is lvalue (there are no rvalues of function type). Hence, rvalue references to function types can bind to function lvalues.

The type of 'i' below in main(). Why is it an int&?

I know the type of i below in main() is an int&. That's why it must be initialized.
int& f(){ static int i = 1; return i; }
int main()
{
decltype(f()) i = f();
}
But using paragraph 5p5 in the Standard, I conclude that the expression f() has type int as the reference is dropped.
From 7.1.6.2p4, how can one say that the expression f() is an lvalue, given that the reference was dropped from the function return?
The reference is dropped when evaluating the type of the expression (as per § 5/5), but this does not change the fact that the function call expression f() is an lvalue. Per paragraph 5.2.2/10 of the C++11 Standard:
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function
type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
In other words, the reference is not dropped from the return type of the function itself, only from the type of the evaluated function call expression (which is, therefore, int).
The fact that the function is returning an lvalue reference is what allows the type system to classify corresponding function call expressions as lvalues - which, in turn, allows decltype to add the lvalue reference to the type of the expression, thus yielding int&.