Question

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]"
Was it helpful?

Solution

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;
}

OTHER TIPS

"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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top