When should you use remove_reference and add_reference?

I look at [VC10's] unique_ptr and they do a couple of things that I don’t understand:

typedef typename tr1::remove_reference<_Dx>::type _Dx_noref; _Dx_noref& get_deleter() { // return reference to deleter return (_Mydel); } unique_ptr(pointer _Ptr, typename _If<tr1::is_reference<_Dx>::value, _Dx, const typename tr1::remove_reference<_Dx>::type&>::_Type _Dt) : _Mybase(_Ptr, _Dt) { // construct with pointer and (maybe const) deleter& } typename tr1::add_reference<_Ty>::type operator*() const { // return reference to object return (*this->_Myptr); } 

Isn't it easy to write _Dx & or _Ty & to be the same?

I really understand why they did it here:

 unique_ptr(pointer _Ptr, typename tr1::remove_reference<_Dx>::type&& _Dt) : _Mybase(_Ptr, _STD move(_Dt)) { // construct by moving deleter } 
+7
source share
3 answers

get_deleter

Any link is removed from the return type, after which the link is returned. In consistent C ++ 11, adding & to the existing & (or && ) creates & . However, in C ++ 03, this will be due to a reference to a reference type that was illegal. MSVC probably uses the old rules, or this code was written when it did, and remains that it is harmless.

Constructor

Here they remove the link, add const , and then add the link back to pass the const link. This is because adding const directly to the reference type does nothing! (Β§8.3.2 / 1) In C ++ 11 or C ++ 03, a parameter declaration will be valid, but will not add const if the link has not been deleted and replaced.

operator*

This is essentially the same as get_deleter , but they went differently, and _Ty cannot be a reference type to start with. It seems to me that _Ty& enough, but this is their prerogative.

+14
source

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.

+2
source

template class add_reference has specialization for void , const void and const volatile void , because the void type (void&) link is not allowed. If _Ty& , it generates a compilation error if _Ty = void .

+1
source

All Articles