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

### 3170. `is_always_equal` added to `std::allocator` makes the standard library treat derived types as always equal

Section: 20.10.9 [default.allocator] Status: WP Submitter: Billy O'Neal III Opened: 2018-11-29 Last modified: 2020-11-09

Priority: 2

View all other issues in [default.allocator].

View all issues with WP status.

Discussion:

I (Billy O'Neal) attempted to change MSVC++'s standard library to avoid instantiating allocators' `operator==` for allocators that are declared `is_always_equal` to reduce the number of template instantiations emitted into .objs.

In so doing I introduced an unrelated bug related to POCMA handling, but it brought my attention to this allocator. This allocator doesn't meet the allocator requirements because it is getting `std::allocator`'s `operator==` and `operator!=` which don't compare the root member. However, if this had been a conforming C++14 allocator with its own `==` and `!=` we would still be treating it as `is_always_equal`, as it picks that up by deriving from `std::allocator`.

`std::allocator` doesn't actually need `is_always_equal` because the defaults provided by `allocator_traits` will say `true_type` for it, since implementers don't make `std::allocator` stateful.

Billy O'Neal thinks this is NAD on the grounds that we need to be able to add things or change the behavior of standard library types.

Stephan T Lavavej thinks we should resolve this anyway because we don't know of an implementation for which this would change the default answer provided by `allocator_traits`.

[2019-02 Priority set to 2 after reflector discussion]

Previous resolution [SUPERSEDED]:

> This wording is relative to N4778.

> 1. Modify 20.10.9 [default.allocator] as follows:

>    > -1- All specializations of the default allocator satisfy the allocator completeness requirements (16.4.4.6.2 [allocator.requirements.completeness]).

>    >     namespace std {
>    >       template<class T> class allocator {
>    >       public:
>    >         using value_type = T;
>    >         using size_type = size_t;
>    >         using difference_type = ptrdiff_t;
>    >         using propagate_on_container_move_assignment = true_type;
>    >         using is_always_equal = true_type;
>    >         constexpr allocator() noexcept;
>    >         constexpr allocator(const allocator&) noexcept;
>    >         template<class U> constexpr allocator(const allocator<U>&) noexcept;
>    >         ~allocator();
>    >         allocator& operator=(const allocator&) = default;
>    >         [[nodiscard]] T* allocate(size_t n);
>    >         void deallocate(T* p, size_t n);
>    >       };
>    >     }

>    > -?- `allocator_traits<allocator<T>>::is_always_equal::value` is `true` for any `T`.

[2019-07 Cologne]

Jonathan provides updated wording.

[2020-10-02; Issue processing telecon: Moved to Tentatively Ready.]

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4820.

1. Modify 20.10.9 [default.allocator] as follows:

   > -1- All specializations of the default allocator satisfy the allocator completeness requirements (16.4.4.6.2 [allocator.requirements.completeness]).

   >     namespace std {
   >       template<class T> class allocator {
   >       public:
   >         using value_type = T;
   >         using size_type = size_t;
   >         using difference_type = ptrdiff_t;
   >         using propagate_on_container_move_assignment = true_type;
   >         using is_always_equal = true_type;
   >         constexpr allocator() noexcept;
   >         constexpr allocator(const allocator&) noexcept;
   >         template<class U> constexpr allocator(const allocator<U>&) noexcept;
   >         ~allocator();
   >         allocator& operator=(const allocator&) = default;
   >         [[nodiscard]] T* allocate(size_t n);
   >         void deallocate(T* p, size_t n);
   >       };
   >     }

   > -?- `allocator_traits<allocator<T>>::is_always_equal::value` is `true` for any `T`.

2. Add a new subclause in Annex D after D.12 [depr.str.strstreams]:

   > D.? The default allocator [depr.default.allocator]

   > -?- The following member is defined in addition to those specified in 20.10.9 [default.allocator]:

   >     namespace std {
   >       template <class T> class allocator {
   >       public:
   >         using is_always_equal = true_type;
   >       };
   >     }