类模板是一种不完全的类型。它需要绑定参数,才能转化成实际的类型。这叫实例化。绑定的模板参数需要是类型,或者是常数。当然最后还有模板。那么如果需要向模板传递模板该怎么办呢?
STL采用了rebind的办法。这是摘自STL allocator内存分配器的代码:
template<typename _Tp>
class new_allocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef const _Tp* const_pointer;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef _Tp value_type;
template<typename _Tp1>
struct rebind
{ typedef new_allocator<_Tp1> other; };
new_allocator() throw() { }
new_allocator(const new_allocator&) throw() { }
template<typename _Tp1>
new_allocator(const new_allocator<_Tp1>&) throw() { }
~new_allocator() throw() { }
pointer
address(reference __x) const { return &__x; }
const_pointer
address(const_reference __x) const { return &__x; }
// NB: __n is permitted to be 0. The C++ standard says nothing
// about what the return value is when __n == 0.
pointer
allocate(size_type __n, const void* = 0)
{ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); }
// __p is not permitted to be a null pointer.
void
deallocate(pointer __p, size_type)
{ ::operator delete(__p); }
size_type
max_size() const throw()
{ return size_t(-1) / sizeof(_Tp); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_] allocator::construct
void
construct(pointer __p, const _Tp& __val)
{ ::new(__p) _Tp(__val); }
void
destroy(pointer __p) { __p->~_Tp(); }
};
这里的allocator模板内部暗藏了一个和自己一模一样的模板:rebind。new_allocator实例化了之后,它通过调用new_allocator::rebind::other又还原了这块代码的模板特性。在STL红黑树实现中,对传入数据类型,添加指针之后,用rebind::other来为红黑树的node分配内存。这里的allocator模板和rebind::other实际是同一个东西。这样就可以为allocator模板中为它的实例化参数类型的导出类型再次安排实例化。例如在红黑树的例子中,导出类型在原来类型的基础上多了3个指针。这会影响allocator分配的大小,但不影响allocator的功能。
那么,可不可以在template 声明中直接传模板呢?比如代码这样写:
template < class T, template < class U > class allocator>
…
用gcc调试证明是可以的。下面是个例子。new_allocator是一个需要一个类型参数的模板,直接用它了:
#include <stdio.h>
#include <ext/new_allocator.h>
template <class T, template<class U>class Alloc=__gnu_cxx::new_allocator>
struct list {
T t;
list *next;
void insert(const T &t);
};
template <class T, template<class U>class Alloc>
void list<T,Alloc>:: insert(const T& t)
{
list *node;
Alloc<list> al;
Alloc<T> at;
node = al.allocate(1);
at.construct(&node->t, t);
node->next=next;
next = node;
}
int main()
{
list<int> l;
l.t=0;
l.next=0;
l.insert(1);
l.insert(2);
l.insert(3);
l.insert(4);
l.insert(5);
list<int> *p;
p = &l;
while(p) {
printf("%d->", p->t);
p= p->next;
}
printf("END\n");
}