std::allocator_traits
works its magic automatically when I provide an STL-style container with an allocator that has a single template parameter but it doesn't when I provide an STL-style container with an allocator that has two template parameters but is otherwise similar.
What do I need to do to tell std::allocator_traits
how to interact with an allocator that has more than one template parameter? Is it possible to get std::allocator_traits
to provide reasonable defaults in this case?
As an example, if I take the simple allocator Howard Hinnant provides in Allocator Boilerplate and feed it to a std::vector<>
then all is well. If I add a dummy int
parameter to the allocator
template (and make slight modifications as needed) then I get compiler errors because the compiler couldn't find rebind
, among other things.
Here's that description in code:
http://coliru.stacked-crooked.com/a/173c57264137a351
If I have to specialize std::allocator_traits
myself in this case, is there a way to still get the defaults?
The Standard only provides a default rebind
for allocators with multiple template type parameters:
17.6.3.5 Allocator requirements [allocator.requirements]
3 Note A: The member class template
rebind
in the table above is effectively a typedef template. [ Note: In general, if the nameAllocator
is bound toSomeAllocator<T>
, thenAllocator::rebind<U>::other
is the same type asSomeAllocator<U>
, whereSomeAllocator<T>::value_type
isT
andSomeAllocator<U>:: value_type
isU
. — end note ] IfAllocator
is a class template instantiation of the formSomeAllocator<T, Args>
, whereArgs
is zero or more type arguments, andAllocator
does not supply arebind
member template, the standard allocator_traits template usesSomeAllocator<U, Args>
> in place ofAllocator:: rebind<U>::other
by default. For allocator types that are not template instantiations of the above form, no default is provided.
Since you have a non-type (int
) parameter, there is no default provided. The fix is simple: just add your own rebind to your allocator.
template<class T, int I>
class allocator_w_int
{
// as before
template<class U>
struct rebind { using other = allocator_w_int<U, I>; };
};
Live Example
As to the rationale of allowing for allocators of the form Allocator<T, Args...>
but not for allocators of the form Alloc<T, Ns...>
, one can only guess, but then it would also lead to the plethora of Alloc<T, Args.., Ns...>
etc. etc.. This is why template-metaprogramming libraries (such as Boost.MPL) always wrap their non-type parameters N
of type T
inside things like integral_constant<T, N>
. This would also be a route for you, by defining
template<class T, class Arg>
class allocator_w_int; // leave undefined
template<int N>
using int_ = std::integral_constant<int, N>;
template<class T, int I>
class allocator_w_int<T, int_<I>>
{
// replace all occurances of I, J --> int_<I>, int_<J>
};
Live Example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With