类模板是一种不完全的类型。它需要绑定参数,才能转化成实际的类型。这个过程叫做实例化。模板的参数必须是常数,或者类型。那么如果需要向模板传递模板该怎么办呢?
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(); }
};
new_allocator实例化了之后,它通过调用new_allocator::rebind::other又还原了这块代码的模板特性。在STL红黑树实现中,对传入数据类型,添加指针之后,用rebind::other来分配node内存。这里的allocator模板和rebind::other实际是一回事。
那么,可不可以在template 声明中直接传模板呢?比如代码这样写:
template < class T, template < class U > class allocator>
…
调试发现,这样写gcc是能够接受的。
#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");
}