(template) rebind<> 做啥?
Posted
技术标签:
【中文标题】(template) rebind<> 做啥?【英文标题】:what does (template) rebind<> do?(template) rebind<> 做什么? 【发布时间】:2013-01-03 23:07:35 【问题描述】:为了进一步了解标准库的实际实现方式,我正在检查 Visual Studio 中的所有容器。这里我看到了一些奇怪的结构:
在std::list<>
的某个基类中找到以下typedef
typedef typename _Alloc::template rebind<_Ty>::other _Alty;
其中“_Alloc”对应于分配器模板参数(和 _Ty 包含的类型)。我很难找到这个“关键字”的好解释。到目前为止我发现的最好的事情是它是分配器接口的一部分。虽然即使cppreference 也不能很好地解释这一点。
template rebind<>
有什么作用?为什么在那个位置有必要?
【问题讨论】:
相关,见Why is allocator::rebind necessary when we have template template parameters? 【参考方案1】:_Alloc
模板用于获取某种类型的对象。容器可能有内部需要分配不同类型的对象。例如,当您有std::list<T, A>
时,分配器A
旨在分配T
类型的对象,但std::list<T, A>
实际上需要分配某些节点类型的对象。调用节点类型_Ty
,std::list<T, A>
需要获取_Ty
对象的分配器,该分配器使用A
提供的分配机制。使用
typename _A::template rebind<_Ty>::other
指定相应的类型。现在,这个声明中有一些语法上的烦恼:
-
由于
rebind
是_A
的成员模板并且_A
是模板参数,所以rebind
成为从属名称。为了表明依赖名称是一个模板,它需要以template
为前缀。如果没有 template
关键字,<
将被视为小于运算符。
名称other
也依赖于模板参数,即它也是一个依赖名称。要表明从属名称是一种类型,需要使用 typename
关键字。
【讨论】:
等等,但这意味着(当列表为std::list<T, A>
时); rebind<T>
变得多余了?因为它会将“T”转换为“T”类型?
@paul23:如果_Ty
是模板参数,而不是typedef _Node<_T> _Ty
之类的参数,则可能有助于确保分配器创建适当的类型。虽然我很确定std::list<T, A>
中的A
需要能够处理T
对象,但可能会传入不同的分配器。我不确定标准要求。它可能是支持不同类型分配器的扩展。
T 的列表分配包含 T 作为成员的节点。所以T分配器直接对它没用。相反,它制作了一个新的。你的评论对我没有意义@paul23
@Yakk:我认为T
类型的分配器用于提取容器中定义的某些类型,例如std::list<T, A>::reference
。但是,std::list<int, std::allocator<long> >
似乎可以编译。如果分配器没有反弹,那么上面列表中的reference
类型将是long&
而不是int&
。
标准要求(在表 99 中)A::value_type
与 std::list<T,A>::value_type
的类型相同,即与 T
的类型相同,因此未定义实例化例如std::list<int, std::allocator<long>>
...但至少 libstdc++(可能还有其他 impls)允许它作为扩展并在内部重新绑定分配器。我不记得他们为什么允许它!【参考方案2】:
rebind
用于为与正在实现的容器的元素类型不同的类型分配内存。取自this MSDN article:
例如,给定 A 类型的分配器对象 al,您可以使用以下表达式分配 _Other 类型的对象:
A::rebind<Other>::other(al).allocate(1, (Other *)0)
或者,您可以通过编写类型来命名其指针类型:A::rebind<Other>::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 在运行时,可以用作功能切换吗?
Rebind and Rewind in Execution Plans