Here is an example, perhaps archetypal, for which we need remove_reference
, in the implementation of std::move
: The goal is to return the link type rvalue based on the inferred type of the function argument.
Example: Foo x; move(x);
Foo x; move(x);
Here move(x)
should return the type Foo&&
. But the move
argument is an expression of type Foo&
. So how does the move
function infer the correct type?
The first attempt is to use the normal output of the template argument and use listing:
template <typename T> T && move(??? x) { return static_cast<T&&>(x); }
But what should go to ???
? If we say T x
, then T
will be printed as Foo&
; if we say T & x
, then T = Foo
, and if we say T && x
, this will not match at all. The second version, T & x
, seems useful.
But then the function does not work for r values ββto start with (for example, move(Foo(...))
. In this case, we want T && x
so that T = Foo
and T&& = Foo&&
if desired. We could have two overloads , but with multiple overloads it is undesirable because it requires complexity once again.And finally, if someone must explicitly specify the template parameter as move<Foo&>(x)
, the function will never work, because when T = Foo&
, then T&& = Foo&
.
So comes remove_reference
:
template <typename T> typename std::remove_reference<T>::type && move(T && x) { return static_cast<typename std::remove_reference<T>::type &&>(x); }
First, the new link folding rules imply that T
is output as Foo&
or Foo&&
in two cases. Then remove_reference
splits the link and gives the type Foo
anyway, and adding &&
makes the desired return type Foo&&
.
In a simplified summary: we need to remove_reference
because (Foo&)&&
is Foo&
, not Foo&&
. If you ever write template code that needs a basic type of template parameter that can be displayed as U&
or U&&
, you can use this model.