operator<=>
on the C++ Standard LibraryDocument Number: P0790R1 Date: 2018-08-06 Author: David Stone (davidmstone@google.com, david@doublewise.net) Audience: LEWG, LWG
This paper lists (what are expected to be) non-controversial changes to the C++ standard library in response to P0515, which adds operator<=>
to the language. This is expected to be non-controversial because it tries to match existing behavior as much as possible. As a result, all proposed additions are either strong_equality
or strong_ordering
, matching the existing comparison operators.
This document should contain a complete list of types or categories of types in C++.
R1: A much broader version of this paper was presented to LEWG at a previous meeting. What remains in this paper is everything which the group did not find controversial and which probably does not require significant justification. All controversial aspects will be submitted in separate papers.
The operator<=>
proposal was written such that the "generated" operators are equivalent to source code rewrites – there is no actual operator==
that a user could take the address of. Users are not allowed to form pointers to standard library member functions and are unable to form pointers to friend functions defined inline in the class. There are some cases where we do not specify how the operator was implemented, only that the expression a @ b
is valid; these cases are not broken by such a change because users could not have depended on it, anyway. In general, we accept changes that overload existing functions, which also has the effect of breaking code which takes the address of a free function.
operator<=>
in this paperThese types are not comparable now. This paper does not propose adding any new comparisons to any of these types.
nothrow
, piecewise_construct_t
, etc.)plus
, minus
, etc.)equal_to
, etc.)owner_less
logical_and
, etc.)bit_and
, etc.)nested_exception
allocator_traits
char_traits
iterator_traits
numeric_limits
pointer_traits
regex_traits
chrono::duration_values
tuple_element
max_align_t
map::node_type
map::insert_return_type
set::node_type
set::insert_return_type
unordered_map::node_type
unordered_map::insert_return_type
unordered_set::node_type
unordered_set::insert_return_type
any
default_delete
aligned_storage
aligned_union
system_clock
steady_clock
high_resolution_clock
locale::facet
locale::id
ctype_base
ctype
ctype_byname
codecvt_base
codecvt
codecvt_byname
num_get
num_put
numpunct
numpunct_byname
collate
collate_byname
time_get
time_get_byname
time_put
time_put_byname
money_base
money_get
money_put
money_punct
moneypunct_byname
message_base
messages
messages_byname
FILE
va_list
back_insert_iterator
front_insert_iterator
insert_iterator
ostream_iterator
ostreambuf_iterator
ios_base
ios_base::Init
basic_ios
basic_streambuf
basic_istream
basic_iostream
basic_ostream
basic_stringbuf
basic_istringstream
basic_ostringstream
basic_stringstream
basic_filebuf
basic_ifstream
basic_ofstream
basic_fstream
gslice
slice_array
gslice_array
mask_array
indirect_array
atomic_flag
thread
mutex
recursive_mutex
timed_mutex
timed_recursive_mutex
lock_guard
scoped_lock
unique_lock
once_flag
shared_mutex
shared_timed_mutex
shared_lock
condition_variable
condition_variable_any
promise
future
shared_future
packaged_task
random_device
hash
weak_ptr
basic_regex
sequential_execution_policy
parallel_execution_policy
parallel_vector_execution_policy
default_searcher
boyer_moore_searcher
boyer_moore_horspool_searcher
ratio
integer_sequence
seed_seq
(paper needed to add strong_equality
)enable_shared_from_this
: It would be nice to give it a strong_ordering
to allow derived classes to = default
. However, this means that all classes that do not explicitly delete their comparison operator get an operator<=>
that compares only the enable_shared_from_this
base class, which is almost certainly wrong. Since this is intended to be used as a base class, we should not add operator<=>
to it. Moreover, classes which enable_shared_from_this
are unlikely to be basic value classes so they do not lose much by not being able to default.initializer_list
: initializer_list
is a reference type. It would be strange to give it reference semantics on copy but value semantics for comparison. It would also be surprising if two initializer_list
containing the same set of values compared as not equal. Therefore, I recommend not defining it for this type.operator<=>
in this paperdiv_t
ldiv_t
lldiv_t
imaxdiv_t
timespec
tm
lconv
fenv_t
fpos_t
mbstate_t
operator<=>
, no change from current comparisonsThese types are all currently comparable.
error_category
: strong_ordering
error_code
: strong_ordering
error_condition
: strong_ordering
exception_ptr
: strong_ordering
type_info
: strong_equality
monostate
: strong_ordering
bitset
: strong_equality
(paper would be needed to change this to strong_ordering
)allocator
: strong_equality
memory_resource
: strong_equality
synchronized_pool_resource
: (implicitly from memory_resource
base class)unsynchronized_pool_resource
: (implicitly from memory_resource
base class)monotonic_buffer_resource
: (implicitly from memory_resource
base class)polymorphic_allocator
: strong_equality
scoped_allocator_adaptor
: strong_equality
pool_options
: strong_equality
function
: strong_equality
with nullptr_t
only (no homogenous operator)chrono::duration
: strong_ordering
, heterogeneous with durations of other representations and periodschrono::time_point
: strong_ordering
, heterogeneous in the durationtype_index
: strong_ordering
locale
: strong_equality
complex
: strong_equality
(heterogeneous with T
and homogeneous)linear_congruential_engine
: strong_equality
mersenne_twister_engine
: strong_equality
subtract_with_carry_engine
: strong_equality
discard_block_engine
: strong_equality
independent_bits_engine
: strong_equality
shuffle_order_engine
: strong_equality
uniform_int_distribution
: strong_equality
uniform_int_distribution::param_type
: strong_equality
uniform_real_distribution
: strong_equality
uniform_real_distribution::param_type
: strong_equality
bernoulli_distribution
: strong_equality
bernoulli_distribution::param_type
: strong_equality
binomial_distribution
: strong_equality
binomial_distribution::param_type
: strong_equality
geometric_distribution
: strong_equality
geometric_distribution::param_type
: strong_equality
negative_binomial_distribution
: strong_equality
negative_binomial_distribution::param_type
: strong_equality
poisson_distribution
: strong_equality
poisson_distribution::param_type
: strong_equality
exponential_distribution
: strong_equality
exponential_distribution::param_type
: strong_equality
gamma_distribution
: strong_equality
gamma_distribution::param_type
: strong_equality
weibull_distribution
: strong_equality
weibull_distribution::param_type
: strong_equality
extreme_value_distribution
: strong_equality
extreme_value_distribution::param_type
: strong_equality
normal_distribution
: strong_equality
normal_distribution::param_type
: strong_equality
lognormal_distribution
: strong_equality
lognormal_distribution::param_type
: strong_equality
chi_squared_distribution
: strong_equality
chi_squared_distribution::param_type
: strong_equality
cauchy_distribution
: strong_equality
cauchy_distribution::param_type
: strong_equality
fisher_f_distribution
: strong_equality
fisher_f_distribution::param_type
: strong_equality
student_t_distribution
: strong_equality
student_t_distribution::param_type
: strong_equality
discrete_distribution
: strong_equality
discrete_distribution::param_type
: strong_equality
piecewsie_constant_distribution
: strong_equality
piecewsie_constant_distribution::param_type
: strong_equality
piecewise_linear_distribution
: strong_equality
piecewise_linear_distribution::param_type
: strong_equality
filesystem::path
: strong_ordering
filesystem::path::iterator
: strong_ordering
filesystem::directory_entry
: strong_ordering
filesystem::directory_iterator
: strong_ordering
filesystem::recursive_directory_iterator
: strong_ordering
istream_iterator
: strong_equality
istreambuf_iterator
: strong_equality
match_results
: strong_equality
regex_iterator
: strong_equality
regex_token_iterator
: strong_equality
thread::id
: strong_ordering
fpos
: strong_equality
array::iterator
: strong_ordering
deque::iterator
: strong_ordering
forward_list::iterator
: strong_equality
list::iterator
: strong_equality
vector::iterator
: strong_ordering
map::iterator
: strong_equality
set::iterator
: strong_equality
multimap::iterator
: strong_equality
multiset::iterator
: strong_equality
unordered_map::iterator
: strong_equality
unodered_set::iterator
: strong_equality
unordered_multimap::iterator
: strong_equality
unodered_multiset::iterator
: strong_equality
valarray::iterator
: strong_ordering
operator<=>
from a conversion operatorThese types will get operator<=>
if possible without any changes, just like they already have whatever comparison operators their underlying type has.
integral_constant
and all types deriving from integral_constant
(has operator T
)bitset::reference
(has operator bool
)reference_wrapper
(has operator T &
)atomic
(has operator T
)This has the disadvantage that types which have a template comparison operator will not have their wrapper convertible. For instance, std::reference_wrapper<std::string>
is not currently comparable. This does not affect bitset::reference
, as it has a fixed conversion to bool
, but it does affect the other three.
array
deque
forward_list
list
vector
(including vector<bool>
)map
set
multimap
multiset
unordered_map
unodered_set
unodered_multimap
unordered_multiset
queue
queue::iterator
priority_queue
priority_queue::iterator
stack
stack::iterator
pair
tuple
reverse_iterator
move_iterator
optional
variant
This turned out to be much more complicated than expected and will require its own paper.
basic_string
, basic_string_view
, char_traits
, and sub_match
Properly integrating operator<=>
with these types requires more thought than this paper has room for, and thus will be discussed separately.
unique_ptr
and shared_ptr
They contain state that is not observed in the comparison operators. Therefore, they will get their own paper.
Current comparison operators return a valarray<bool>
, giving you the result for each pair (with undefined behavior for differently-sized valarray
arguments). It might make sense to provide some sort of function that returns valarray<comparison_category>
, but that should not be named operator<=>
. This paper does not suggest adding operator<=>
to valarray
.
operator<=>
in another paperThis paper does not propose changing any of the following types -- they are here only for completeness.
filesystem::file_status
filesystem::space_info
slice
to_chars_result
from_chars_result
nullptr_t
Already supports strong_equality
in the working draft. I will be writing a separate paper proposing strong_ordering
.
This category includes things like BinaryPredicate
and Compare
. This is addressed in a separate paper.
This includes things like LessThanComparable
and EqualityComparable
. This is addressed in a separate paper.
All operator<=>
should be constexpr
and noexcept
where possible, following the lead of the language feature and allowing = default
as an implementation strategy for some types.
When we list a result type as "unspecified" it is unspecified whether it has operator<=>
. There are not any unspecified result types for which we currently guarantee any comparison operators are present, so there is no extra work to do here.