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
rebindin the table above is effectively a typedef template. [ Note: In general, if the nameAllocatoris bound toSomeAllocator<T>, thenAllocator::rebind<U>::otheris the same type asSomeAllocator<U>, whereSomeAllocator<T>::value_typeisTandSomeAllocator<U>:: value_typeisU. — end note ] IfAllocatoris a class template instantiation of the formSomeAllocator<T, Args>, whereArgsis zero or more type arguments, andAllocatordoes not supply arebindmember template, the standard allocator_traits template usesSomeAllocator<U, Args>> in place ofAllocator:: rebind<U>::otherby 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