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
*/