Search code examples
c++c++11rvalue-reference

what's the magic of std:move


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);
    }
  1. The argument of move is still a rvalue reference,but move(str) is ok!
  2. move also returns rvalue.

What's the magic of std:move?

Thanks


Solution

  • 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.