title: Using a custom allocator inside a std::scoped_allocator_adaptor with std::unordered_map
body: <p>I'm trying to use a simple memory pool allocator with <code>std::unordered_map</code>. I have used this same allocator seemingly successfully with both <code>std::string</code> and <code>std::vector</code>. I want the items contained in the unordered_map (and vector) to also use this allocator so I've wrapped my allocator in <code>std::scoped_allocator_adaptor</code>.</p>
  
  <p>Simplified definition set:</p>
  
  <pre><code>template &lt;typename T&gt;
  using mm_alloc = std::scoped_allocator_adaptor&lt;lake_alloc&lt;T&gt;&gt;;
  
  using mm_string = std::basic_string&lt;char, std::char_traits&lt;char&gt;, mm_alloc&lt;char&gt;&gt;;
  using mm_vector = std::vector&lt;mm_string, mm_alloc&lt;mm_string&gt;&gt;;
  using mm_map = std::unordered_map&lt;mm_string, mm_vector, std::hash&lt;mm_string&gt;, std::equal_to&lt;mm_string&gt;, mm_alloc&lt;std::pair&lt;mm_string, mm_vector&gt;&gt;&gt;;
  </code></pre>
  
  <p>Initialised as such:</p>
  
  <pre><code>lake pool;
  mm_map map { mm_alloc&lt;std::pair&lt;mm_string, mm_vector&gt;&gt;{pool} };
  </code></pre>
  
  <p><code>lake_alloc</code> is shown below with the rest of the iterator code. The error I'm getting in Clang 3.3 is that it cannot its <code>allocator_type</code> (in this case the mm_alloc of the pair of string to vector) to its own <code>__pointer_allocator</code>. That is an internal type used for the hash map implementation. Partial error output below:</p>
  
  <pre><code>lib/c++/v1/__hash_table:848:53: error: no matching conversion for functional-style
        cast from 'const allocator_type' (aka 'const std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;std::__1::pair&lt;std::__1::basic_string&lt;char,
        std::__1::char_traits&lt;char&gt;, std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;, std::__1::vector&lt;std::__1::basic_string&lt;char,
        std::__1::char_traits&lt;char&gt;, std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;,
        std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;,
        std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;, krystal::lake&gt; &gt; &gt; &gt;, krystal::lake&gt; &gt;') to '__pointer_allocator' (aka
        'std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;std::__1::__hash_node&lt;std::__1::pair&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;,
        std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;, std::__1::vector&lt;std::__1::basic_string&lt;char, std::__1::char_traits&lt;char&gt;,
        std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;, std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;std::__1::basic_string&lt;char,
        std::__1::char_traits&lt;char&gt;, std::__1::scoped_allocator_adaptor&lt;krystal::krystal_alloc&lt;char, krystal::lake&gt; &gt; &gt;, krystal::lake&gt; &gt; &gt; &gt;, void *&gt; *, krystal::lake&gt; &gt;')
      : __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
                                                      ^~~~~~~~~~~~~~~~~~~~~~~
  </code></pre>
  
  <p>GCC 4.7.1 gives me a similar error in its hash map internal structures so clearly I'm doing it wrong but this is my first foray in allocators in the STL and I'm at a loss.</p>
  
  <p>The custom allocator follows, It's a simple implementation with some holes in it but this version works well in a contained test case with a couple of megs of data in vectors and strings.</p>
  
  <pre><code>#include &lt;cstddef&gt;
  #include &lt;memory&gt;
  #include &lt;scoped_allocator&gt;
  
  class lake {
      const size_t block_size_;
      mutable std::vector&lt;std::unique_ptr&lt;uint8_t[]&gt;&gt; blocks_;
      mutable uint8_t *arena_, *pos_;
  
      static constexpr const size_t DefaultBlockSize = 48 * 1024;
  
      void add_block(size_t of_size) const {
          blocks_.emplace_back(new uint8_t[of_size]);
          pos_ = arena_ = blocks_.back().get();
      }
  
      inline void add_block() const { add_block(block_size_); }
  
  public:
      lake(const size_t block_size)
      : block_size_ {block_size}
      {
          add_block();
      }
      lake() : lake(DefaultBlockSize) {}
  
      void* allocate(size_t n) const {
          if (pos_ + n - arena_ &gt; block_size_) {
              if (n &gt; block_size_)
                  add_block(n); // single-use large block
              else
                  add_block();
          }
  
          auto result = pos_;
          pos_ += n;
          return result;
      }
  
      void deallocate(void* p, size_t n) const {
      }
  };
  
  
  template &lt;typename T, typename Alloc&gt;
  class krystal_alloc {
      const Alloc* allocator_;
  
  public:
      using value_type = T;
      using size_type = size_t;
      using difference_type = ptrdiff_t;
      using pointer = T*;
      using const_pointer = const T*;
      using reference = T&amp;;
      using const_reference = const T&amp;;
  
      template &lt;typename U&gt;
      struct rebind { typedef krystal_alloc&lt;U, Alloc&gt; other; };
  
      krystal_alloc() : allocator_{ new Alloc() } {} // not used
      krystal_alloc(const Alloc&amp; alloc) : allocator_{ &amp;alloc } {}
  
      pointer address(reference v) {
          return 0;
      }
  
      const_pointer address(const_reference v) {
          return 0;
      }
  
      size_type max_size() const {
          return static_cast&lt;size_type&gt;(-1) / sizeof(value_type);
      }
  
      pointer allocate(size_type n) {
          return static_cast&lt;pointer&gt;(allocator_-&gt;allocate(sizeof(T) * n));
      }
  
      void deallocate(pointer p, size_type n) {
          allocator_-&gt;deallocate(p, n);
      }
  };
  
  template &lt;typename T, typename Alloc, typename U&gt;
  inline bool operator==(const krystal_alloc&lt;T, Alloc&gt;&amp;, const krystal_alloc&lt;U, Alloc&gt;) { return true; }
  
  template &lt;typename T, typename Alloc, typename U&gt;
  inline bool operator!=(const krystal_alloc&lt;T, Alloc&gt;&amp;, const krystal_alloc&lt;U, Alloc&gt;) { return false; }
  
  
  // -- standard usage
  template &lt;typename T&gt;
  using lake_alloc = krystal_alloc&lt;T, lake&gt;;
  </code></pre>