(template) rebind<> 做啥?

Posted

技术标签:

【中文标题】(template) rebind<> 做啥?【英文标题】:what does (template) rebind<> do?(template) rebind<> 做什么? 【发布时间】:2013-01-03 23:07:35 【问题描述】:

为了进一步了解标准库的实际实现方式,我正在检查 Visual Studio 中的所有容器。这里我看到了一些奇怪的结构:

std::list&lt;&gt;的某个基类中找到以下typedef

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

其中“_Alloc”对应于分配器模板参数(和 _Ty 包含的类型)。我很难找到这个“关键字”的好解释。到目前为止我发现的最好的事情是它是分配器接口的一部分。虽然即使cppreference 也不能很好地解释这一点。

template rebind&lt;&gt; 有什么作用?为什么在那个位置有必要?

【问题讨论】:

相关,见Why is allocator::rebind necessary when we have template template parameters? 【参考方案1】:

_Alloc 模板用于获取某种类型的对象。容器可能有内部需要分配不同类型的对象。例如,当您有std::list&lt;T, A&gt; 时,分配器A 旨在分配T 类型的对象,但std::list&lt;T, A&gt; 实际上需要分配某些节点类型的对象。调用节点类型_Tystd::list&lt;T, A&gt; 需要获取_Ty 对象的分配器,该分配器使用A 提供的分配机制。使用

typename _A::template rebind<_Ty>::other

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

    由于rebind_A 的成员模板并且_A 是模板参数,所以rebind 成为从属名称。为了表明依赖名称是一个模板,它需要以template 为前缀。如果没有 template 关键字,&lt; 将被视为小于运算符。 名称other 也依赖于模板参数,即它也是一个依赖名称。要表明从属名称是一种类型,需要使用 typename 关键字。

【讨论】:

等等,但这意味着(当列表为std::list&lt;T, A&gt;时); rebind&lt;T&gt; 变得多余了?因为它会将“T”转换为“T”类型? @paul23:如果_Ty 是模板参数,而不是typedef _Node&lt;_T&gt; _Ty 之类的参数,则可能有助于确保分配器创建适当的类型。虽然我很确定std::list&lt;T, A&gt; 中的A 需要能够处理T 对象,但可能会传入不同的分配器。我不确定标准要求。它可能是支持不同类型分配器的扩展。 T 的列表分配包含 T 作为成员的节点。所以T分配器直接对它没用。相反,它制作了一个新的。你的评论对我没有意义@paul23 @Yakk:我认为T 类型的分配器用于提取容器中定义的某些类型,例如std::list&lt;T, A&gt;::reference。但是,std::list&lt;int, std::allocator&lt;long&gt; &gt; 似乎可以编译。如果分配器没有反弹,那么上面列表中的reference 类型将是long&amp; 而不是int&amp; 标准要求(在表 99 中)A::value_typestd::list&lt;T,A&gt;::value_type 的类型相同,即与 T 的类型相同,因此未定义实例化例如std::list&lt;int, std::allocator&lt;long&gt;&gt; ...但至少 libstdc++(可能还有其他 impls)允许它作为扩展并在内部重新绑定分配器。我不记得他们为什么允许它!【参考方案2】:

rebind 用于为与正在实现的容器的元素类型不同的类型分配内存。取自this MSDN article:

例如,给定 A 类型的分配器对象 al,您可以使用以下表达式分配 _Other 类型的对象:A::rebind&lt;Other&gt;::other(al).allocate(1, (Other *)0) 或者,您可以通过编写类型来命名其指针类型:A::rebind&lt;Other&gt;::other::pointer

【讨论】:

【参考方案3】:

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 中,其中内部列表节点也需要它的分配器,它是从参数分配器重新定义的。

【讨论】:

【参考方案4】:

请查看http://www.cplusplus.com/reference/memory/allocator/

你会看到

rebind<...> 实际上是类分配器的成员,它是 STL 的一部分,没有给出实现的源代码。

如你所见,rebind<...> 也是一个模板,它应该有一个类型让分配器类知道我的 rebind 成员中有什么。

回到你的陈述: typedef typename _Alloc::template rebind<_ty>::other _Alty; 如果您省略了模板: typedef typename _Alloc::rebind<_ty>::other _Alty; 你可以很容易理解 rebind 是 _Alloc 的成员,但是编译器无法理解。

鉴于 rebind 是模板的性质,模板 rebind<_ty> 是必需的并被处理 整体不是两部分。

【讨论】:

以上是关于(template) rebind<> 做啥?的主要内容,如果未能解决你的问题,请参考以下文章

Ninject Rebind 在运行时,可以用作功能切换吗?

db2 reorg runstats rebind具体操作

markdown ahk rebind默认

Rebind and Rewind in Execution Plans

Rust variable rebinding for closure

浅析DNS Rebinding