Created on 2022-03-18.00:00:00 last changed 24 months ago
Proposed resolution:
This wording is relative to N4901.
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();
}
};
}
[ 2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP. ]
[ 2022-07-15; LWG telecon: move to Ready ]
[ 2022-05-17; Reflector poll ]
Set status to Tentatively Ready after six votes in favour during reflector poll.
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:43 | admin | set | status: wp -> c++23 |
| 2022-07-25 20:32:58 | admin | set | messages: + msg12640 |
| 2022-07-25 20:32:58 | admin | set | status: ready -> wp |
| 2022-07-25 20:28:19 | admin | set | messages: + msg12614 |
| 2022-05-17 11:57:24 | admin | set | messages: + msg12452 |
| 2022-05-17 11:57:24 | admin | set | status: new -> ready |
| 2022-03-19 20:14:52 | admin | set | messages: + msg12407 |
| 2022-03-18 00:00:00 | admin | create | |