operator==
for polymorphic_allocator
cannot deduce template argument in common casesSection: 20.4.3 [mem.poly.allocator.class] Status: C++23 Submitter: Pablo Halpern Opened: 2022-03-18 Last modified: 2023-11-22
Priority: Not Prioritized
View all other issues in [mem.poly.allocator.class].
View all issues with C++23 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.
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
.
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
.
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.
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(); } }; }