Let's start with the move function (which I cleaned up a bit):
template <typename T> typename remove_reference<T>::type&& move(T&& arg) { return static_cast<typename remove_reference<T>::type&&>(arg); }
Let's start with the simpler part - that is, when a function is called with rvalue:
Object a = std::move(Object());
and our move template gets an instance as follows:
// move with [T = Object]: remove_reference<Object>::type&& move(Object&& arg) { return static_cast<remove_reference<Object>::type&&>(arg); }
Since remove_reference converts T& to T or T&& to T , and Object not a reference, our final function:
Object&& move(Object&& arg) { return static_cast<Object&&>(arg); }
Now you might think: do we even need a cast? Answer: yes, we do. The reason is simple; the specified rvalue reference is treated as an lvalue (and the implicit conversion from lvalue to rvalue reference is prohibited by the standard).
This is what happens when we call move with an lvalue:
Object a;
and the corresponding move instance:
// move with [T = Object&] remove_reference<Object&>::type&& move(Object& && arg) { return static_cast<remove_reference<Object&>::type&&>(arg); }
Again, remove_reference converts Object& to Object and we get:
Object&& move(Object& && arg) { return static_cast<Object&&>(arg); }
Now we move on to the difficult part: what does Object& && mean and how can it communicate with lvalue?
To ensure perfect forwarding, the C ++ 11 standard provides special rules for collapsing links, which are as follows:
Object & & = Object & Object & && = Object & Object && & = Object & Object && && = Object &&
As you can see, according to these rules, Object& && actually means Object& , which is a simple lvalue reference that allows you to bind lvalues.
Final function:
Object&& move(Object& arg) { return static_cast<Object&&>(arg); }
which is not like the previous instance with rvalue - they both pass their argument to the rvalue reference and then return it. The difference is that the first instance can only be used with rvalues, and the second with lvalues.
To explain why we need remove_reference little more, try this function
template <typename T> T&& wanna_be_move(T&& arg) { return static_cast<T&&>(arg); }
and create it using lvalue.
// wanna_be_move [with T = Object&] Object& && wanna_be_move(Object& && arg) { return static_cast<Object& &&>(arg); }
Applying the above rules for dropping links, you can see that we get a function that is not suitable for use as move (just, you call it lvalue, you get lvalue back). In any case, this function is an identity function.
Object& wanna_be_move(Object& arg) { return static_cast<Object&>(arg); }