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.

### 3683. `operator==` for `polymorphic_allocator` cannot deduce template argument in common cases

Section: 20.4.3 [mem.poly.allocator.class] Status: WP Submitter: Pablo Halpern Opened: 2022-03-18 Last modified: 2022-07-25

Priority: Not Prioritized

View all other issues in [mem.poly.allocator.class].

View all issues with WP status.

Discussion:

In `<memory_resource>`, the equality comparison operator for `pmr::polymorphic_allocator` is declared in namespace scope as:

>     template<class T1, class T2>
>       bool operator==(const polymorphic_allocator<T1>& a,
>                       const polymorphic_allocator<T2>& b) noexcept;

Since `polymorphic_allocator` is implicitly convertible from `memory_resource*`, one would naively expect — and the author of `polymorphic_allocator` intended — the following code to work:

>     std::pmr::unsynchronized_pool_resource pool_rsrc;
>     std::pmr::vector<int> vec(&pool_rsrc); // Converts to std::pmr::polymorphic_allocator<int>
>     […]
>     assert(vec.get_allocator() == &pool_rsrc);  // (1) Compare polymorphic_allocator to memory_resource*

Unfortunately, the line labeled (1) is ill-formed because the type `T2` in `operator==` cannot be deduced.

Possible resolution 1 (PR1) is to supply a second `operator==`, overloaded for comparison to `memory_resource*`:

>     template<class T1, class T2>
>       bool operator==(const polymorphic_allocator<T1>& a,
>                       const polymorphic_allocator<T2>& b) noexcept;
>     template<class T>
>       bool operator==(const polymorphic_allocator<T>& a,
>                       memory_resource* b) noexcept;

The rules for implicitly defined spaceship and comparison operators obviates defining `operator!=` or `operator==(b, a)`. This PR would allow `polymorphic_allocator` to be compared for equality with `memory_resource*`, but not with any other type that is convertible to `polymorphic_allocator`.

Possible resolution 2 (PR2) is to replace `operator==` with a homogeneous version where type deduction occurs only for one template parameter:

>     template<class T1, class T2>
>       bool operator==(const polymorphic_allocator<T1>& a,
>                       const polymorphic_allocator<T2>& b) noexcept;
>     template<class T>
>       bool operator==(const polymorphic_allocator<T>& a,
>                       const type_identity_t<polymorphic_allocator<T>>& b) noexcept;

This version will work with any type that is convertible to `polymorphic_allocator`.

Possible resolution 3 (PR3), the proposed resolution, below, is to add a homogeneous equality operator as a "hidden friend", such that it is found by ADL only if one argument is a `polymorphic_allocator` and the other argument is convertible to `polymorphic_allocator`. As with PR2, this PR will work with any type that is convertible to `polymorphic_allocator`.

> Note to reader: Proof of concept for the three possible resolutions can be seen at this godbolt link. Uncomment one of PR1, PR2, or PR3 macros to see the effects of each PR.

[2022-05-17; Reflector poll]

Set status to Tentatively Ready after six votes in favour during reflector poll.

[2022-07-15; LWG telecon: move to Ready]

[2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP.]

Proposed resolution:

This wording is relative to N4901.

1. Modify 20.4.3 [mem.poly.allocator.class], class template `polymorphic_allocator` synopsis, as indicated:

   >     namespace std::pmr {
   >       template<class Tp = byte> class polymorphic_allocator {
   >         memory_resource* memory_rsrc; // exposition only

   >       public:
   >         using value_type = Tp;

   >         […]
   >         memory_resource* resource() const;

   >         // friends
   >         friend bool operator==(const polymorphic_allocator& a,
   >                                const polymorphic_allocator& b) noexcept {
   >           return *a.resource() == *b.resource();
   >         }
   >       };
   >     }