“template rebind<>”是什么意思?

44

我正在尝试学习有关标准库实际实现的更多信息,检查Visual Studio中的所有容器。在这里,我看到一些奇怪的结构:

std::list<>的某个基类中发现了以下typedef。

typedef typename _Alloc::template rebind<_Ty>::other _Alty;

在这里,"_Alloc" 对应的是分配器模板参数(_Ty是被包含的类型)。我很难找到关于这个 "keyword" 的好解释。到目前为止,我找到的最好的东西是它是分配器接口的一部分。尽管甚至cppreference也无法很好地解释。

template rebind<> 是什么作用?为什么需要在那个位置?


4个回答

50
_Alloc模板用于获取某种类型的对象。容器可能有内部需要分配不同类型对象的需求。例如,当您拥有一个std::list<T, A>时,分配器A用于分配类型为T的对象,但实际上std::list<T, A>需要分配某些节点类型的对象。将节点类型称为_Tystd::list<T, A>需要获取一个为_Ty对象分配内存的分配器,该分配器使用由A提供的分配机制。
typename _A::template rebind<_Ty>::other

指定相应的类型。现在,在此声明中有一些语法上的烦恼:

  1. 由于rebind_A的成员模板,而_A是一个模板参数,因此rebind变成了一个依赖名称。为了表示依赖名称是一个模板,需要在其前面加上template。如果没有template关键字,则<将被视为小于运算符。
  2. 名称other也依赖于一个模板参数,即它也是一个依赖名称。为了表示依赖名称是一个类型,需要使用typename关键字。

等等,这是否意味着(当列表是std::list<T, A>时)rebind<T>变得多余了?因为它会将“T”转换为“T”类型? - paul23
如果_Ty是模板参数,而不是像typedef _Node<_T> _Ty这样的东西,那么确保分配器创建适当类型可能会很有用。虽然我相当确定std::list<T, A>中的A需要能够处理T对象,但是可能会传入不同类型的分配器。我不确定标准要求。支持不同类型的分配器可能是一种扩展。 - Dietmar Kühl
节点列表分配了包含T成员的节点。因此,T分配器对它本身来说是无用的。相反,它会创建一个新的分配器。@paul23,您的评论对我来说没有意义。 - Yakk - Adam Nevraumont
@Yakk:我认为类型T的分配器用于提取容器中定义的某些类型,例如std::list<T, A>::reference。然而,似乎std::list<int, std::allocator<long>>可以编译通过。如果未重新绑定分配器,则上述列表中的reference类型将是long&而不是int& - Dietmar Kühl
标准要求(在表99中)A::value_type 是与 std::list<T,A>::value_type 相同的类型,即与 T 相同的类型,因此实例化例如 std::list<int, std::allocator<long>> 是未定义的...但至少 libstdc++(和可能其他实现)允许它作为扩展并在内部重新绑定分配器。我不记得他们为什么允许它了! - Jonathan Wakely
显示剩余2条评论

10

rebind用于为实现的容器元素类型不同的类型分配内存。引用自此MSDN文章:

例如,给定类型为A的分配器对象al,您可以使用表达式分配类型为_Other的对象:

A::rebind<Other>::other(al).allocate(1, (Other *)0)

或者,您可以通过编写类型来为其指针命名:

A::rebind<Other>::other::pointer

6

在stdc++的代码示例中,/usr/include/4.8/ext/new_allocator.h文件中:

rebind被定义为分配器类的结构成员;该结构定义了一个成员other,它被定义为专门针对不同参数类型进行特化的分配器实例(other成员定义了一个分配器类,可以创建不同类型的对象)。

 template<typename _Tp>
    class new_allocator
    {
    public:
      ...
      template<typename _Tp1>
        struct rebind
        { typedef new_allocator<_Tp1> other; };

什么时候使用:

  typedef typename _Alloc::template rebind<_Tp>::other _Tp_alloc_type;

分配器的类型被称为引用。
  typename _Alloc::template rebind<_Tp>::other 

现在使用typedef来定义_Tp_alloc_type,这样就可以将其作为相同事物的更短名称使用。
一个示例用法是在std::list中,其中内部列表节点也需要其分配器,该分配器从参数分配器重新定义。

-1
请检查此链接http://www.cplusplus.com/reference/memory/allocator/ 您将会看到
rebind<...>实际上是STL的allocator类的成员,而不需要提供实现的源代码。
正如您所看到的,rebind<...>也是一个模板,并且它需要一个类型来让allocator类知道我的rebind成员中有什么。
因此回到您的语句: typedef typename _Alloc::template rebind<_Ty>::other _Alty; 如果您省略了模板: typedef typename _Alloc::rebind<_Ty>::other _Alty; 您可以轻松理解rebind是_Alloc的成员,但编译器无法理解。
考虑到rebind的本质是模板,因此需要模板rebind<_Ty>,并且被视为整体而不是两个部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接