This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

### 3431. `<=>` for containers should require `three_way_comparable<T>` instead of `<=>`

Section: 22.2.1 [container.requirements.general] Status: New Submitter: Jonathan Wakely Opened: 2020-04-17 Last modified: 2020-09-06

Priority: 2

View other active issues in [container.requirements.general].

View all other issues in [container.requirements.general].

View all issues with New status.

Discussion:

The precondition for `<=>` on containers is:

"Either `<=>` is defined for values of type (possibly `const`) `T`, or `<` is defined for values of type (possibly `const`) `T` and `<` is a total ordering relationship."

I don't think `<=>` is sufficient, because `synth-three-way` won't use `<=>` unless `three_way_comparable<T>` is satisfied, which requires `weakly-equality-comparable-with<T, T>` as well as `<=>`.

So to use `<=>` I think the type also requires `==`, or more precisely, it must satisfy `three_way_comparable`.

The problem becomes clearer with the following example:

>     #include <compare>
>     #include <vector>

>     struct X
>     {
>       friend std::strong_ordering operator<=>(X, X) { return std::strong_ordering::equal; }
>     };

>     std::vector<X> v(1);
>     std::strong_ordering c = v <=> v;

This doesn't compile, because despite `X` meeting the preconditions for `<=>` in [tab:container.opt], `synth-three-way` will return `std::weak_ordering`.

Here is another example:

>     #include <compare>
>     #include <vector>

>     struct X
>     {
>       friend bool operator<(X, X) { return true; } // The return value is intentional, see below
>       friend std::strong_ordering operator<=>(X, X) { return std::strong_ordering::equal; }
>     };

>     std::vector<X> v(1);
>     std::weak_ordering c = v <=> v;

This meets the precondition because it defines `<=>`, but the result of `<=>` on `vector<X>` will be nonsense, because `synth-three-way` will use `operator<` not `operator<=>` and that defines a broken ordering.

So we're stating a precondition which implies "if you do this, you don't get garbage results" and then we give garbage results anyway.

The proposed resolution is one way to fix that, by tightening the precondition so that it matches what `synth-three-way` actually does.

[2020-04-25 Issue Prioritization]

Priority to 2 after reflector discussion.

Proposed resolution:

This wording is relative to N4861.

1. Modify 22.2.1 [container.requirements.general], Table [tab:container.opt], as indicated:

   > Table 75: Optional container operations [tab:container.opt]
   > Expression | Return type | Operational semantics | Assertion/note pre-/post-condition | Complexity
   > --- | --- | --- | --- | ---
   > `…`
   > `a <=> b` | `synth-three-way-result<value_type>` | `lexicographical_compare_three_way( a.begin(), a.end(), b.begin(), b.end(), synth-three-way)` | Preconditions: Either `<=>` is defined for values of type (possibly `const`) `T` satisfies `three_way_comparable`, or `<` is defined for values of type (possibly `const`) `T` and `<` is a total ordering relationship. | linear
   > `…`