Title
operator== for polymorphic_allocator cannot deduce template argument in common cases
Status
c++23
Section
[mem.poly.allocator.class]
Submitter
Pablo Halpern

Created on 2022-03-18.00:00:00 last changed 13 months ago

Messages

Date: 2022-07-25.20:32:58

Proposed resolution:

This wording is relative to N4901.

  1. Modify [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();
        }
      };
    }
    
Date: 2022-07-25.00:00:00

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

Date: 2022-07-15.00:00:00

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

Date: 2022-05-15.00:00:00

[ 2022-05-17; Reflector poll ]

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

Date: 2022-03-19.20:21:02

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.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2022-07-25 20:32:58adminsetmessages: + msg12640
2022-07-25 20:32:58adminsetstatus: ready -> wp
2022-07-25 20:28:19adminsetmessages: + msg12614
2022-05-17 11:57:24adminsetmessages: + msg12452
2022-05-17 11:57:24adminsetstatus: new -> ready
2022-03-19 20:14:52adminsetmessages: + msg12407
2022-03-18 00:00:00admincreate