Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is allocator::rebind necessary when we have template template parameters?

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.

like image 645
user541686 Avatar asked Sep 11 '12 03:09

user541686


People also ask

What is allocator rebind?

rebind is defined as a structure member of the allocator class; this structure defines a member other that is defined as an instance of the allocator specialized for a different argument type (the other member defines an allocator class that can creates a different type of objects) template<typename _Tp> class ...

Why do we use template template parameter?

Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

What is correct for template parameter?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

What can the template parameter in C++ template definition be?

In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

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++.

like image 144
incises Avatar answered Sep 18 '22 19:09

incises


But why is this necessary?

What if your allocator class has more than one template argument?

That's pretty much it in terms of why it is generally discouraged to use template template arguments, in favor of using normal template arguments, even if it means a bit of redundancy at the instantiation site. In many cases (however, probably not for allocators), that argument might not always be a class template (e.g., a normal class with template member functions).

You might find it convenient (within the implementation of the container class) to use a template template parameter just because it simplifies some of the internal syntax. However, if the user has a multi-argument class template as an allocator he wants to use, but you require the user to provide an allocator which is a single-argument class template, you will in effect force him to create a wrapper for almost any new context in which he must use that allocator. This not only unscalable, it can also become very inconvenient to do. And, at this point, that solution is far from being the "elegant and less redundant" solution you originally thought it would be. Say you had an allocator with two arguments, which of the following is the easiest for the user?

std::vector<T, my_allocator<T,Arg2> > v1;  std::vector<T, my_allocator_wrapper<Arg2>::template type > v2; 

You basically force the user to construct a lot of useless things (wrappers, template aliases, etc.) just to satisfy your implementation's demands. Requiring the author of a custom allocator class to supply a nested rebind template (which is just a trivial template alias) is far easier than all the contortions you require with the alternative approach.

like image 24
Mikael Persson Avatar answered Sep 19 '22 19:09

Mikael Persson