且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

当我们有模板模板参数时,为什么需要 allocator::rebind ?

更新时间:2023-11-30 22:07:22

引用自 C++11 中的算法基础,第 1 卷,第 4 章,p.35 :

template 结构分配器{模板使用 rebind = allocator;};

示例用法:

allocator::rebindX;

C++ 编程语言,第 4 版,第 34.4.1 节,p.998,评论默认分配器类中的经典"重新绑定成员:

templatestruct rebind { using other = allocator;};

Bjarne Stroustrup 写道:

奇怪的重新绑定模板是一个古老的别名.应该是:

template使用 other = allocator;

但是,分配器是在 C++ 支持此类别名之前定义的.

Every allocator class must have an interface similar to the following:

template<class T>
class allocator
{
    ...
    template<class Other>
    struct rebind { typedef allocator<Other> other; };
};

And classes that use allocators do something redundant like this:

template<class T, class Alloc = std::allocator<T> >
class vector { ... };

But why is this necessary?

In other words, couldn't they have just said:

template<class T>
class allocator { ... };

template<class T, template<class> class Alloc = std::allocator>
class vector { ... };

which is both more elegant, less redundant, and (in some similar situations) potentially safer?
Why did they go the rebind route, which also causes more redundancy (i.e. you have to say T twice)?

(Similar question goes to char_traits and the rest... although they don't all have rebind, they could still benefit from template template parameters.)


Edit:

But this won't work if you need more than 1 template parameter!

Actually, it works very well!

template<unsigned int PoolSize>
struct pool
{
    template<class T>
    struct allocator
    {
        T pool[PoolSize];

        ...
    };
};

Now if vector was only defined this way:

template<class T, template<class> class Alloc>
class vector { ... };

Then you could just say:

typedef vector<int, pool<1>::allocator> int_vector;

And it would work perfectly well, without needing you to (redundantly) say int twice.

And a rebind operation inside vector would just become Alloc<Other> instead of Alloc::template rebind<Other>::other.

A quoted text from Foundations of Algorithms in C++11, Volume 1, chap 4, p. 35 :

template <typename T> 
struct allocator 
{  
   template <typename U>  
   using  rebind = allocator<U>; 
}; 

sample usage :

allocator<int>::rebind<char> x;


In The C++ Programming Language, 4th edition, section 34.4.1, p. 998, commenting the 'classical' rebind member in default allocator class :

template<typename U>
     struct rebind { using other = allocator<U>;};

Bjarne Stroustrup writes this:

The curious rebind template is an archaic alias. It should have been:

template<typename U>
using other = allocator<U>;

However, allocator was defined before such aliases were supported by C++.