我什么时候应该使用remove_reference和add_reference?

时间:2012-01-14 04:49:39

标签: c++ c++11

我正在看[VC10的] unique_ptr,他们做了一些我不明白的事情:

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);
    }

不只是写_Dx&amp;或_Ty&amp;是一回事吗?

我确实理解他们为什么在这里做到了:

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

3 个答案:

答案 0 :(得分:14)

get_deleter

从返回类型中删除任何引用,然后添加引用。在符合C ++ 11的情况下,向现有&(或&)添加&&会产生&。然而,在C ++ 03中,这将形成对引用类型的引用,这是非法的。可能MSVC正在使用旧规则,或者代码是在它执行时编写的,因为它是无害的。

构造

在这里,他们删除引用,添加const,然后添加引用,以便通过const引用。这是因为直接向引用类型添加const nothing ! (§8.3.2/ 1)在C ++ 11或C ++ 03中,参数声明有效,但如果未删除和替换引用,则不会添加const

operator*

这与get_deleter基本相同,但它们以不同的方式进行,_Ty不能作为参考类型开始。在我看来,_Ty&就足够了,但这是他们的特权。

答案 1 :(得分:3)

这是一个示例,可能是原型,为什么我们需要remove_reference,在std::move的实现中:目标是返回一个基于推导的rvalue-reference类型函数参数的类型。

示例:Foo x; move(x);此处move(x)应返回类型Foo&&。但move的论点是Foo&类型的表达式。那么move函数如何推导出正确的类型?

第一次尝试是使用普通模板参数推导并使用强制转换:

template <typename T> T && move(??? x) { return static_cast<T&&>(x); }

但是???应该怎么做?如果我们说T x,那么T将被推断为Foo&;如果我们说T & x,然后T = Foo,如果我们说T && x,则根本不匹配。第二个版本T & x似乎很有用。

但是该函数在rvalues上不起作用(例如move(Foo(...))。在这种情况下,我们需要T && x以便根据需要T = FooT&& = Foo&&我们可能有两个重载,但是有多个重载是不可取的,因为它会不必要地增加复杂性。最后,如果有人明确地将模板参数指定为move<Foo&>(x),那么该函数永远不会工作,因为T = Foo&时,然后是T&& = Foo&

所以来remove_reference

template <typename T>
typename std::remove_reference<T>::type && move(T && x)
{
    return static_cast<typename std::remove_reference<T>::type &&>(x);
}

首先,新参考折叠规则意味着T在两种情况下推断为Foo&Foo&&。然后,remove_reference会删除引用,并在任何情况下都会提供Foo类型,添加&&会生成所需的Foo&&返回类型。

在过于简化的摘要中:我们需要remove_reference因为(Foo&)&&Foo&而不是Foo&&。如果您编写的模板代码需要模板参数的基本类型(可以推导为U&U&&),则可以使用此模型。

答案 2 :(得分:1)

template class add_reference专门针对voidconst voidconst volatile void,因为不允许引用void type (void&)。如果使用_Ty&,则会在_Ty = void时生成编译错误。