10 Classes [class]

10.10 Comparisons [class.compare]

10.10.1 Defaulted comparison operator functions [class.compare.default]

A defaulted comparison operator function ([expr.spaceship], [expr.rel], [expr.eq]) for some class C shall be a non-template function declared in the member-specification of C that is
  • a non-static member of C having one parameter of type const C&, or
  • a friend of C having two parameters of type const C&.
A three-way comparison operator for a class type C is a structural comparison operator if it is defined as defaulted in the definition of C, and all three-way comparison operators it invokes are structural comparison operators.
A type T has strong structural equality if, for a glvalue x of type const T, x <=> x is a valid expression of type std::strong_­ordering or std::strong_­equality and either does not invoke a three-way comparison operator or invokes a structural comparison operator.

10.10.2 Three-way comparison [class.spaceship]

The direct base class subobjects of C, in the order of their declaration in the base-specifier-list of C, followed by the non-static data members of C, in the order of their declaration in the member-specification of C, form a list of subobjects.
In that list, any subobject of array type is recursively expanded to the sequence of its elements, in the order of increasing subscript.
Let x be an lvalue denoting the element in the expanded list of subobjects for an object x (of length n), where x is formed by a sequence of derived-to-base conversions ([over.best.ics]), class member access expressions ([expr.ref]), and array subscript expressions ([expr.sub]) applied to x.
The type of the expression x <=> x is denoted by R.
It is unspecified whether virtual base class subobjects are compared more than once.
If the declared return type of a defaulted three-way comparison operator function is auto, then the return type is deduced as the common comparison type (see below) of R, R, , R.
[Note
:
Otherwise, the program will be ill-formed if the expression x <=> x is not implicitly convertible to the declared return type for any i.
end note
]
If the return type is deduced as void, the operator function is defined as deleted.
The return value V of type R of the defaulted three-way comparison operator function with parameters x and y of the same type is determined by comparing corresponding elements x and y in the expanded lists of subobjects for x and y until the first index i where x <=> y yields a result value v where v, contextually converted to bool, yields true; V is v converted to R.
If no such index exists, V is std::strong_­ordering::equal converted to R.
The common comparison type U of a possibly-empty list of n types T, T, , T is defined as follows:
  • If any T is not a comparison category type ([cmp.categories]), U is void.
  • Otherwise, if at least one T is std::weak_­equality, or at least one T is std::strong_­equality and at least one T is std::partial_­ordering or std::weak_­ordering, U is std::weak_­equality ([cmp.weakeq]).
  • Otherwise, if at least one T is std::strong_­equality, U is std::strong_­equality ([cmp.strongeq]).
  • Otherwise, if at least one T is std::partial_­ordering, U is std::partial_­ordering ([cmp.partialord]).
  • Otherwise, if at least one T is std::weak_­ordering, U is std::weak_­ordering ([cmp.weakord]).
  • Otherwise, U is std::strong_­ordering ([cmp.strongord]).
    [Note
    :
    In particular, this is the result when n is 0.
    end note
    ]

10.10.3 Other comparison operators [class.rel.eq]

A defaulted relational ([expr.rel]) or equality ([expr.eq]) operator function for some operator @ shall have a declared return type bool.
The operator function with parameters x and y is defined as deleted if
  • overload resolution ([over.match]), as applied to x <=> y (also considering synthesized candidates with reversed order of parameters ([over.match.oper])), results in an ambiguity or a function that is deleted or inaccessible from the operator function, or
  • the operator @ cannot be applied to the return type of x <=> y or y <=> x.
Otherwise, the operator function yields x <=> y @ 0 if an operator<=> with the original order of parameters was selected, or 0 @ y <=> x otherwise.
[Example
:
struct C {
  friend std::strong_equality operator<=>(const C&, const C&);
  friend bool operator==(const C& x, const C& y) = default; // OK, returns x <=> y == 0
  bool operator<(const C&) = default;                       // OK, function is deleted
};
end example
]