This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.

### 2311. Allocator requirements should be further minimized

Section: 16.4.4.6 [allocator.requirements] Status: NAD Submitter: Stephan T. Lavavej Opened: 2013-09-21 Last modified: 2016-01-28

Priority: 2

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

C++11's minimized allocator requirements are great, but they're still requiring more things from users than absolutely necessary.

- They require `X::value_type`, but that can be deduced from `SomeAllocator<T, Args>`.

- They require `a1 == a2`, but that could default to `true` as most allocators are stateless.

- They require `a1 != a2`, but if we start requiring STL implementations to go through `allocator_traits` to provide an `op==` default, we won't need to require `op!=` from users at all. (`std::allocator`, of course, would continue to provide `op!=`. Note that this is analogous to `reference`/`const_reference` — `std::allocator` still provides them, but we don't require them from users, and in fact we don't require them to be consistent or meaningful if present.)

- They require `a == b` and `a != b`. This requirement was not present in C++98/03, it is not necessary (`a == b` is always required to be equivalent to rebind-then-compare), and STL implementations don't even need to compare allocators of different types directly.

[2014-02-14 Issaquah: Close as NAD]

Different vendors rely on each of the different elements suggested to be removed.

While `value_type` my be deduced as suggested, far too much wording relies on it being available, and the standard churn is likely to be much harder than presented here.

Proposed resolution:

This wording is relative to N3691.

1. Change in 16.4.4.6 [allocator.requirements], Table 28 — "Allocator requirements" as indicated:

   > Table 28 — Allocator requirements (continued)
   > Expression | Return type | Assertion/note pre-/post-condition | Default
   > --- | --- | --- | ---
   > `…`
   > `X::value_type` | Identical to `T` |  | See Note B, below.
   > `…`
   > `a1 == a2` | `bool` | returns `true` only if storage allocated from each can be deallocated via the other. `operator==` shall be reflexive, symmetric, and transitive, and shall not exit via an exception. | `true`
   > `a1 != a2` | `bool` | same as `!(a1 == a2)` |
   > `a == b` | `bool` | same as `a == Y::rebind<T>::other(b)` |
   > `a != b` | `bool` | same as `!(a == b)` |
   > `…`
   > `X a(b);` |  | Shall not exit via an exception. post: `Y(a) == b`, `a == X(b)` |
   > `…`
   > `X a(move(b));` |  | Shall not exit via an exception. post: `a` equals the prior value of `X(b)`. |
   > `…`

2. After 16.4.4.6 [allocator.requirements] p3, add a new paragraph:

   > Note B: If `Allocator` is a class template instantiation of the form `SomeAllocator<T, Args>`, where `Args` is zero or more type arguments, and `Allocator` does not supply a nested type named `value_type`, the standard `allocator_traits` template uses `T` in place of `Allocator::value_type` by default. For allocator types that are not template instantiations of the above form, no default is provided.

3. In the example provided in 16.4.4.6 [allocator.requirements]/5, delete as indicated:

   >     template <class Tp>
   >     struct SimpleAllocator {
   >       typedef Tp value_type;
   >       SimpleAllocator(ctor args);
   >       template <class T> SimpleAllocator(const SimpleAllocator<T>& other);
   >       Tp *allocate(std::size_t n);
   >       void deallocate(Tp *p, std::size_t n);
   >     };

   >     template <class T, class U>
   >     bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
   >     template <class T, class U>
   >     bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&);

4. Edit 20.2.9 [allocator.traits]p1, class template `allocator_traits` synopsis, as indicated:

   >     namespace std {
   >       template <class Alloc> struct allocator_traits {
   >         typedef Alloc allocator_type;

   >         typedef typename Alloc::value_typesee below value_type;

   >         […]

   >         static Alloc select_on_container_copy_construction(const Alloc& rhs);

   >         static bool equal(const Alloc& a1, const Alloc& a2) noexcept;
   >       };
   >     }

5. At the beginning of 20.2.9.2 [allocator.traits.types], add a new paragraph:

   >     typedef see below value_type;

   > > Type: `Alloc::value_type` if such a type exists; otherwise, `T` if `Alloc` is a class template instantiation of the form `Alloc<T, Args>`, where `Args` is zero or more type arguments; otherwise, the program is ill-formed.

6. At the end of 20.2.9.3 [allocator.traits.members], add a new paragraph:

   >     static bool equal(const Alloc& a1, const Alloc& a2) noexcept;

   > > -?- Returns: `a1 == a2` if that expression is well-formed; otherwise, `true`.