C++ Logo

std-discussion

Advanced search

compare_three_way_result and three_way_comparable

From: Nicholas Schwab <cpp_std_at_[hidden]>
Date: Tue, 26 Jan 2021 22:35:32 +0100
Hi,

I noticed a discrepancy for between std::compare_three_way_result and
std::three_way_comparable. The standard defines them as follows:

template<class T, class U = T>
using compare_three_way_result_t = decltype(
     std::declval<const std::remove_reference_t<T>&>() <=>
     std::declval<const std::remove_reference_t<U>&>()
);

[1] and

template<class T, class Cat = partial_ordering>
   concept three_­way_­comparable =
     weakly-equality-comparable-with<T, T> &&
     partially-ordered-with<T, T> &&
     requires(const remove_reference_t<T>& a, const
remove_reference_t<T>& b) {
       { a <=> b } -> compares-as<Cat>;
     };

[2] where

template<class T, class U>
   concept weakly-equality-comparable-with = // exposition only
     requires(const remove_reference_t<T>& t,
              const remove_reference_t<U>& u) {
       { t == u } -> boolean-testable;
       { t != u } -> boolean-testable;
       { u == t } -> boolean-testable;
       { u != t } -> boolean-testable;
     };


[3] Now, if you write a class like this

struct foo {
     std::strong_ordering operator<=>(const foo&) {
      // Some non-defaulted implementation
     }
};

it holds

static_assert(std::is_same_v<std::compare_three_way_result_t<foo,foo>,
std::strong_ordering>>);
static_assert(!std::three_way_comparable<foo>);

This comes from the fact, that paper P1185 [4] disallows obtaining
operator== from operator<=>. I concur with the reasoning in that paper,
but the discrepancy between compare_three_way_result and
three_way_comparable seems counter-intuitive to me. It also has effects
such as:

foo{} <=> foo{}; // is fine
std::optional<foo>{} <=> std::optional<foo>{} // ill-formed

since operator<=> for optional<T> requires three_way_comparable<T>.

Is there a reason for this behavior that I am not aware of? If not, I
would propose that compare_three_way_result_t<T,U> should require
three_way_comparable_with<T,U> to fix this.

Best Wishes,
Nicholas

Links for the above:

[1] http://eel.is/c++draft/cmp#result
[2] http://eel.is/c++draft/cmp#concept:three_way_comparable
[3]
http://eel.is/c++draft/concept.equalitycomparable#concept:weakly-equality-comparable-with
[4] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r2.html

Received on 2021-01-26 15:35:37