Home > Back-end >  Is returned object form a fuction how's return type is rvalue reference, a rvalue or a lvalue?
Is returned object form a fuction how's return type is rvalue reference, a rvalue or a lvalue?

Time:06-07

I am new to c . For this code

template <typename T>
constexpr bool is_lvalue(T&& x) {
  return std::is_lvalue_reference<T>{};
}

int x=9;

int & fun(){
  return x;
}

is_lvalue(fun()) return true. And This I understand, as lvalue reference are afterall lvalues. But for code,

int && fun(){
  return move(x);
}

is_lvalue(fun()) return False, even when variable declared as rvalue reference are also lvalues. So, is second fun() returning a rvalue? Thanks in advance.

CodePudding user response:

A function call expression (like fun()) to a function which returns a rvalue reference is itself a xvalue expression. This is different from naming a variable which is of rvalue reference type. The name of a variable as an expression is always an lvalue, independent of the type of the variable.

A xvalue is a kind of rvalue. The other kind of rvalue being prvalues (which you get for e.g. function calls returning non-references).

Your function tests whether the expression is an lvalue, which a xvalue is not.

x itself used in an expression is an lvalue, but std::move's only job is to take an lvalue and turn it into a xvalue. So move(x) is a xvalue as well.

CodePudding user response:

The std::move(x) casts the x to become an xvalue, which allows it to be moved from. For objects that have resources, those resources can be efficiently moved to the other object. For primitive types, a "move" is a no-op, since there are no "resources" to change ownership.

Caution: the return std::move(x); casting can interfere with NRVO, RVO, and copy elision. Not in this particular case, with an int, but for heavier weight objects it can be a pessimization.

/*
lvalue should had been named something like "variable"
prvalue should had been named something like "temporary"

lvalue - left-hand value (call it "variable")
rvalue - right-hand value (call it "temporary", except when it isn't)
prvalue - pure right-hand value (call it "anonymous temporary")
xvalue - expiring value 
glvalue - generalized left-hand value 

                  glvalue        rvalue
                  / (i) \        / (m)\
                 /       \      /      \     
"variable" lvalue         xvalue        prvalue "temporary"
            (iM) \         (im)        / (Im) |\
                  bitfield        vexpr       | pmfcall
                                              |     
                                               \     
                                                closure

i - identity
m - can be moved from
I - does not have identity (anonymous)
M - cannot be moved from

xvalue - value has identity and can be moved 
lvalue - value has identity and cannot be moved 
prvalue - value does not have identity and can be moved 
bitfield - is a special kind of lvalue
 - address CANNOT be taken 
 - non-const lvalue reference CANNOT be bound to it 
vexpr - is a special kind of prvalue
 - CANNOT be used to initialize references
 - CANNOT be used as function argument
pmfcall - is a special kind of prvalue
 - CANNOT be used to initialize references
 - CANNOT be used as function argument
 - CANNOT be used for any purpose at all, except...
 - can ONLY be used left-hand argument of functional call operator
*/
  • Related