This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.
three_way_comparable_with
is inconsistent with similar conceptsSection: 17.11.4 [cmp.concept] Status: C++20 Submitter: Casey Carter Opened: 2019-12-18 Last modified: 2021-02-25
Priority: 0
View all other issues in [cmp.concept].
View all issues with C++20 status.
Discussion:
The concept three_way_comparable_with
is defined in 17.11.4 [cmp.concept] as:
template<class T, class U, class Cat = partial_ordering> concept three_way_comparable_with = weakly-equality-comparable-with<T, U> && partially-ordered-with<T, U> && three_way_comparable<T, Cat> && three_way_comparable<U, Cat> && common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> && three_way_comparable< common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> && requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) { { t <=> u } -> compares-as<Cat>; { u <=> t } -> compares-as<Cat>; };
Which notably doesn't follow the requirement ordering:
same-type requirements on T
same-type requirements on U
common_reference_with
requirement
same-type requirements on common_reference_t<T, U>
cross-type requirements on T
and U
that the other cross-type comparison concepts (18.5.4 [concept.equalitycomparable], 18.5.5 [concept.totallyordered]) use. There were some motivating reasons for that ordering:
The existence of a common reference type is effectively an opt-in to cross-type concepts. Avoiding checking cross-type expressions when no common reference type exists can enable the concepts to work even in the presence of poorly-constrained "accidental" cross-type operator templates which could otherwise produce compile errors instead of dissatisfied concepts.
Putting the simpler same-type requirements first can help produce simpler error messages
when applying the wrong concept to a pair of types, or the right concept to the wrong pair of types.
"Frobnozzle <=> Frobnozzle
is not a valid expression" is more easily deciphered than
is "std::common_reference<int, FrobNozzle>
has no member named type".
three_way_comparable_with
should be made consistent with equality_comparable_with
and
totally_ordered_with
for the above reasons and to make it easier to reason about comparison concepts
in general.
[2020-01 Status set to Tentatively Ready after five positive votes on the reflector.]
Proposed resolution:
This wording is relative to N4842.
Modify 17.11.4 [cmp.concept] as indicated:
template<class T, class U, class Cat = partial_ordering> concept three_way_comparable_with =weakly-equality-comparable-with<T, U> &&partially-ordered-with<T, U> &&three_way_comparable<T, Cat> && three_way_comparable<U, Cat> && common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> && three_way_comparable< common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> && weakly-equality-comparable-with<T, U> && partially-ordered-with<T, U> && requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) { { t <=> u } -> compares-as<Cat>; { u <=> t } -> compares-as<Cat>; };