Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does std::allocator_traits define rebind_alloc if rebind not present in custom allocator?

I'm trying to rebind my custom allocator type, MyAllocator<foo>, for use in a basic_string class, e.g.:

std::basic_string<char, std::char_traits<char>, MyAllocator<char>> ...

The allocator is passed to the context as MyAllocator<void>, so I need to rebind the allocator.

From the cppreference page for std::allocator_traits, http://en.cppreference.com/w/cpp/memory/allocator_traits:

Member alias templates:

rebind_alloc<T>: Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc is Alloc<U, Args>

My custom allocator implements allocator_traits, but does not define the rebind struct (which doesn't appear to be a requirement to implement allocator_traits). My understanding of the documentation is that it allocator_traits should understand rebind_alloc. However, if I try calling rebind_alloc on my custom allocator type:

template<typename T>
using RebindAlloc =
  typename std::allocator_traits<MyAllocator<void>>::template rebind_alloc<T>;

I get various compiler errors when I try to pass RebindAlloc<char> to the basic_string type:

In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/string:52:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/basic_string.h:114:41: error: 
  'rebind' following the 'template' keyword does not refer to a template
  typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type;

Clearly the documentation has misled me. Should I just give up on rebind_alloc and implement rebind in the custom allocator, or is there a correct way of doing this using allocator_traits?

I am using gcc 4.8 with C++11. 14 is not an option at the moment.

Here's a code snippet of what I'm trying to do: https://gist.github.com/jacquelinekay/0cee73d1d2d78d8edd31

like image 564
Jackie Avatar asked Oct 21 '15 17:10

Jackie


2 Answers

I am using gcc 4.8 with C++11.

Then you need to define rebind in your allocator, GCC's basic_string doesn't support the C++11 allocator requirements until version 5.1 (and then only for the new ABI string, i.e. std::__cxx::basic_string).

So your allocator must meet the C++03 Allocator requirements, defining all the members, because allocator_traits isn't used by string in 4.8

like image 112
Jonathan Wakely Avatar answered Nov 16 '22 01:11

Jonathan Wakely


n3376 says in [allocator.traits.types]/10:

template <class T> using rebind_alloc = see below;

Alias template: Alloc::rebind<T>::other if such a type exists; otherwise, Alloc<T, Args> if Alloc is a class template instantiation of the form Alloc<U, Args>, where Args is zero or more type arguments; otherwise, the instantiation of rebind_alloc is ill-formed.

which agrees with cppreference. It (allocator traits) seem to have been added in C++11, so it does not appear in n1905. Further archaeology could detect where it arrived, but that isn't all that relevant.

It appears as if your compiler is not a compliant C++11 compiler in this regard.

With minor fixes, both gcc 5.2.0 and clang 3.7.0 in C++11 mode will compile your code without error.

It appears the only reasonable response, if you cannot change your compiler, is to implement a simple rebind.

like image 22
Yakk - Adam Nevraumont Avatar answered Nov 16 '22 02:11

Yakk - Adam Nevraumont