is_always_equal
added to std::allocator
makes the standard library treat
derived types as always equalSection: 20.2.10 [default.allocator] Status: C++23 Submitter: Billy O'Neal III Opened: 2018-11-29 Last modified: 2023-11-22
Priority: 2
View other active issues in [default.allocator].
View all other issues in [default.allocator].
View all issues with C++23 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.
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.
Modify 20.2.10 [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
istrue
for anyT
.
[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.
Modify 20.2.10 [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
istrue
for anyT
.
Add a new subclause in Annex D after 99 [depr.str.strstreams]:
D.? The default allocator [depr.default.allocator]
-?- The following member is defined in addition to those specified in 20.2.10 [default.allocator]:namespace std { template <class T> class allocator { public: using is_always_equal = true_type; }; }