This may be obvious but I think it is something difficult to me. Given this:
void test(std::string&&) { }
std::string x{\"test\"};
test(std::move(x)
In simple terms:
&&
can bind to non-const rvalues (prvalues and xvalues)const &&
can bind to rvalues (const and non-const)&
can bind to non-const lvaluesconst &
can bind to rvalues (prvalues and xvalues) and lvalues (const and non-const for each). A.k.a. to anything.If you want a function to expressly allow const-Lvalue objects, but expressly disallow Rvalue objects, write the function signature like this:
void test(const std::string&) { }
void test(std::string&&) = delete;//Will now be considered when matching signatures
int main() {
std::string string = "test";
test(string);//OK
//test(std::move(string));//Compile Error!
//test("Test2");//Compile Error!
}
When you call std::move(x)
, an rvalue
reference to the underlying data, test
, will be returned. You are allowed to pass rvalue
references as const
(and const only!) reference parameters because an rvalue
reference is implicitly convertible to a const
reference. They are arguably the same thing from the function's point of view (a read only parameter). If you removed the const-qualifier of your parameter, this code would not compile:
void other_test(std::string&) { }
std::string x{"test"};
other_test(std::move(x)); //not okay because
//the function can potentially modify the parameter.
See Bo Qian's youtube video on rvalue vs lvalue.
std::move
doesn't actually move anything out of it's own. It's just a fancy name for a cast to a T&&
. Calling test
like this test(std::move(x));
only shows that a T&&
is implicitly convertible to a const T&
. The compiler sees that test
only accepts const T&
so it converts the T&&
returned from std::move
to a const T&
, that's all there is to it.
test(std::string&& a) { something(a) //--> not moved because it has lvalue
Names of variables are lvalues. a
is a name of a variable, therefore a
is an lvalue expression, and therefore it will not be moved from.
It's unclear what you mean by "has". a
is an expression. It is a name of a reference, and references refer to objects. Value categories pertain to expressions, not objects.
test(const std::string& a)
: a is const lvalue reference and like before I have lvalue and rvalue. And plus more, in this case if I calledstd::move(a)
where a is a const& the move works!
If by "works" you mean that it invokes a move constructor or assignment, then no, it does not work because no move construction or assignment has happened.