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 const member of C having one parameter of type const C&, or
- a friend of C having two parameters of type const C&.

A defaulted comparison operator function for class C
is defined as deleted if
any non-static data member of C is of reference type or
C is a union-like class ([class.union.anon]).

If the class definition
does not explicitly declare an == operator function,
but declares a defaulted three-way comparison operator function,
an == operator function is declared implicitly
with the same access as the three-way comparison operator function.

The implicitly-declared == operator for a class X
is an inline member and is defined as defaulted in the definition of X.

If the three-way comparison operator function
is declared as a non-static const member,
the implicitly-declared == operator function is a member of the form

bool X::operator==(const X&) const;

Otherwise, the implicitly-declared == operator function is of the form

friend bool operator==(const X&, const X&);

[ Note

The operator is a constexpr function if its definition
would satisfy the requirements for a constexpr function.: Such a friend function is visible
to argument-dependent lookup ([basic.lookup.argdep])
only ([namespace.memdef]). — *end note*

]A type C has *strong structural equality* if,
given a glvalue x of type const C, either:

- C is a non-class type and x <=> x is a valid expression of type std::strong_ordering or std::strong_equality, or
- C is a class type
where all of the following hold:
- All of C's base class subobjects and non-static data members have strong structural equality.
- C has no mutable or volatile non-static data members.
- At the end of the definition of C, overload resolution performed for the expression x == x succeeds and finds either a friend or public member == operator that is defined as defaulted in the definition of C.

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 be an lvalue denoting the element
in the expanded list of subobjects for an object x
(of length n),
where 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.

It is unspecified whether virtual base class subobjects
appear more than once in the expanded list of subobjects.

A defaulted == operator function for a class C
is defined as deleted
unless, for each in the expanded list of subobjects
for an object x of type C,
is a valid expression and
contextually convertible to bool.

The return value V of a defaulted == operator function
with parameters x and y is determined
by comparing corresponding elements and
in the expanded lists of subobjects for x and y
(in increasing index order)
until the first index i
where yields a result value which,
when contextually converted to bool, yields false.

A defaulted != operator function for a class C
with parameters x and y is defined as deleted if

- overload resolution ([over.match]), as applied to x == y, does not result in a usable function, or
- x == y is not a prvalue of type bool.

Otherwise, the operator function yields !(x == y).

The *synthesized three-way comparison*
for comparison category type R ([cmp.categories])
of glvalues a and b of the same type
is defined as follows:

- If overload resolution for a <=> b finds a usable function ([over.match]), static_cast<R>(a <=> b).
- Otherwise, if overload resolution for a <=> b finds at least one viable candidate, the synthesized three-way comparison is not defined.
- Otherwise, if R is strong_ordering, then
a == b ? strong_ordering::equal : a < b ? strong_ordering::less : strong_ordering::greater

- Otherwise, if R is weak_ordering, then
a == b ? weak_ordering::equal : a < b ? weak_ordering::less : weak_ordering::greater

- Otherwise, if R is partial_ordering, then
a == b ? partial_ordering::equivalent : a < b ? partial_ordering::less : b < a ? partial_ordering::greater : partial_ordering::unordered

- Otherwise, if R is strong_equality, then
a == b ? strong_equality::equal : strong_equality::nonequal

- Otherwise, if R is weak_equality, then
a == b ? weak_equality::equivalent : weak_equality::nonequivalent

- Otherwise, the synthesized three-way comparison is not defined.

Given an expanded list of subobjects for an object x of type C,
the type of the expression <=>
is denoted by .

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
, , …, .

If the return type is deduced as void,
the operator function is defined as deleted.

If the declared return type of
a defaulted three-way comparison operator function
is R
and the synthesized three-way comparison
for comparison category type R
between any objects and
is not defined or would be ill-formed,
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
and
in the expanded lists of subobjects for x and y
(in increasing index order)
until the first index i where
the synthesized three-way comparison for comparison category type R
between and
yields a result value where ,
contextually converted to bool, yields true;
V is .

- Otherwise, if at least one is std::weak_equality, or at least one is std::strong_equality and at least one is std::partial_ordering or std::weak_ordering, U is std::weak_equality ([cmp.weakeq]).
- Otherwise, if at least one is std::strong_equality, U is std::strong_equality ([cmp.strongeq]).
- Otherwise, if at least one is std::partial_ordering, U is std::partial_ordering ([cmp.partialord]).

A defaulted relational ([expr.rel]) 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, does not result in a usable function, or
- the operator @ cannot be applied to the return type of x <=> y.

Otherwise, the operator function yields
x <=> y @ 0.