【发布时间】:2012-09-03 22:47:39
【问题描述】:
每个分配器类都必须有一个类似于以下的接口:
template<class T>
class allocator
{
...
template<class Other>
struct rebind { typedef allocator<Other> other; };
};
使用分配器的类会做一些像这样的冗余操作:
template<class T, class Alloc = std::allocator<T> >
class vector { ... };
但是为什么这是必要的呢?
换句话说,他们不能说:
template<class T>
class allocator { ... };
template<class T, template<class> class Alloc = std::allocator>
class vector { ... };
哪个更优雅,更少冗余,并且(在某些类似情况下)可能更安全?
为什么他们走rebind 路线,这也会导致更多冗余(即您必须说两次T)?
(类似的问题转到char_traits 和其余的......虽然他们不都有rebind,但他们仍然可以从模板模板参数中受益。)
编辑:
但如果您需要超过 1 个模板参数,这将不起作用!
其实效果很好!
template<unsigned int PoolSize>
struct pool
{
template<class T>
struct allocator
{
T pool[PoolSize];
...
};
};
现在如果 vector 只是这样定义的:
template<class T, template<class> class Alloc>
class vector { ... };
那么你可以说:
typedef vector<int, pool<1>::allocator> int_vector;
而且它会很好地工作,不需要你(多余地)说两次int。
而vector 中的rebind 操作将变成Alloc<Other> 而不是Alloc::template rebind<Other>::other。
【问题讨论】:
-
请注意,在 C++11 中,要求放宽了,如果
SomeAllocator不提供rebind,则std::allocator_traits<SomeAllocator<T, Args...>>::rebind_alloc<U>是SomeAllocator<U, Args...>作为合理的默认值。 -
到编辑的最后一点:重新绑定操作在向量实现中看起来有多丑是无关紧要的。你,实施者,有责任让用户的事情变得简单,即使这意味着非常丑陋和复杂的代码。如果您可以将丑陋隐藏在实现中以留下更干净的界面,那么您的工作就是这样做。
-
@MikaelPersson:当然,但是是对用户来说更容易吗? (怎么会?示例/比较会有所帮助!:D)
-
真相可能令人失望。模板重新绑定习惯用旧编译器可能更容易实现。我发现模板模板参数只在较新的 STL 代码中传递。所以并不是说实现者一般不喜欢模板模板参数。我个人喜欢模板模板参数的一点是,仅在句法分析之后,特定意图在接口级别就已经可见,即传递一种 strategy 供内部私有通用使用。
-
如果
pool<1>::allocator<char>::rebind<int>::other需要是pool<4>::allocator<int>。
标签: c++ templates allocator template-templates