The following codes make VC2010 fail :
//code1
std::string& test1(std::string&& x){
return x;
}
std::string str("xxx");
test1(str); //#1 You cannot bind an lvalue to an rvalue reference
//code2
std::string&& test1(std::string&& x){
return x; //#2 You cannot bind an lvalue to an rvalue reference
}
There are some articles to explain #1, but I don't understand why #2 also fails.
let's see how std::move implements
template<class _Ty> inline
typename tr1::_Remove_reference<_Ty>::_Type&&
move(_Ty&& _Arg)
{ // forward _Arg as movable
return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);
}
What's the magic of std:move?
Thanks
std::move
's parameter looks like it is an rvalue reference, which does seem confusing - why can you call move(str)
, when str
is not an rvalue?
The trick here is that rvalue references work confusingly on template parameters:
If template parameter T
is int
, then T&&
will be an rvalue reference int&&
.
But if T
is an lvalue refernce int&
, then T&&
will also be lvalue reference int&
.
This is because of the way &
and &&
combine:
Type & && == Type &
Type && & == Type &
Type & & == Type &
Type && && == Type &&
So when you call move(str)
, T
is std::string&
, and the parameter type of move<std::string&>
is also std::string&
- an lvalue reference, which allows the function call to compile. Then all move
has to do is cast the value to an rvalue reference.