Title
three_way_comparable_with is inconsistent with similar concepts
Status
c++20
Section
[cmp.concept]
Submitter
Casey Carter

Created on 2019-12-18.00:00:00 last changed 38 months ago

Messages

Date: 2020-01-05.16:13:01

Proposed resolution:

This wording is relative to N4842.

  1. Modify [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>;
        };
    
Date: 2020-01-05.16:13:01

[ 2020-01 Status set to Tentatively Ready after five positive votes on the reflector. ]

Date: 2019-12-18.00:00:00

The concept three_way_comparable_with is defined in [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:

  1. same-type requirements on T

  2. same-type requirements on U

  3. common_reference_with requirement

  4. same-type requirements on common_reference_t<T, U>

  5. cross-type requirements on T and U

that the other cross-type comparison concepts ([concept.equalitycomparable], [concept.totallyordered]) use. There were some motivating reasons for that ordering:

  1. 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.

  2. 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.

History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2020-02-24 16:02:59adminsetstatus: voting -> wp
2020-01-17 04:54:50adminsetstatus: ready -> voting
2020-01-05 16:13:01adminsetmessages: + msg10910
2020-01-05 16:13:01adminsetstatus: new -> ready
2019-12-21 14:36:49adminsetmessages: + msg10899
2019-12-18 00:00:00admincreate