It seems both answers are correct , I am just adding paragraph from the standard that explains why it's correct to use std::move()
in line #6
and line #13
and why it's is an lvalue even though the type is an rvalue in line #6
.
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.
5.1.1[expr.prim.general]/8
So applying this rule from the standard we can hopefully get our answers straight.
lvalue
// move_me is identifier of a variable denotes to itself the result is lvalue
std::string move_me = "Some string";
rvalue
// constructing temporary e.g no identifier is an rvalue
std::string("Some string") ;
lvalue
// the variable data has type rvalue reference to move_ms, it denotes entity move_ms
// the result is lvalue
void set_data(std::string&& data);
lvalue
// the variable data has type lvalue reference to move_ms,
//it denotes entity move_ms the result is lvalue
void set_data(std::string& data);
lvalue or rvalue - Universal references
//the variable data has type universal reference it either holds lvalue or rvalue
template<typename T> void setdata(T && data) ;
So, rvalue reference is not rvalue , things can go wrong
Base(Base const & rhs); // non-move semantics
Base(Base&& rhs); // move semantics
if you miss to use std::move()
Derived(Derived&& rhs) : Base(rhs) // wrong: rhs is an lvalue
{
// Derived-specific stuff
}
The correct version is :
Derived(Derived&& rhs) : Base(std::move(rhs)) // good, calls Base(Base&& rhs)
{
// Derived-specific stuff
}
Also
- creating lvalue reference to lvalue - OK
- creating rvalue reference to rvalue - OK
- creating lvalue const reference to rvalue - OK
- creating lvalue reference to rvalue - compile ERROR