A defaulted comparison operator function ([over.binary])
for some class C
shall be a non-template function
that is

- a non-static member or friend of C and
- either has two parameters of type const C& or two parameters of type C, where the implicit object parameter (if any) is considered to be the first parameter.

Name lookups in the implicit definition ([dcl.fct.def.default])
of a comparison operator function
are performed from a context equivalent to
its *function-body*.

A definition of a comparison operator as
defaulted that appears in a class shall be the first declaration
of that function.

A defaulted <=> or == operator function for class C
is defined as deleted if
any non-static data member of C is of reference type or
C has variant members ([class.union.anon]).

A binary operator expression a @ b is
*usable*
if either

- a or b is of class or enumeration type and overload resolution ([over.match]) as applied to a @ b results in a usable candidate, or
- neither a nor b is of class or enumeration type and a @ b is a valid expression.

If the *member-specification*
does not explicitly declare
any member or friend named operator==,
an == operator function is declared implicitly
for each three-way comparison operator function
defined as defaulted in the *member-specification*,
with the same access and *function-definition* and
in the same class scope as
the respective three-way comparison operator function,
except that the return type is replaced with bool and
the *declarator-id* is replaced with operator==.

[*Note 1*: *end note*]

Such an implicitly-declared == operator for a class X
is defined as defaulted
in the definition of X and
has the same *parameter-declaration-clause* and
trailing *requires-clause* as
the respective three-way comparison operator.

It is declared with friend, virtual, constexpr,
or consteval if
the three-way comparison operator function is so declared.

If the three-way comparison operator function
has no *noexcept-specifier*,
the implicitly-declared == operator function
has an implicit exception specification ([except.spec]) that
can differ from the implicit exception specification of
the three-way comparison operator function.

— [*Example 1*: template<typename T> struct X {
friend constexpr std::partial_ordering operator<=>(X, X) requires (sizeof(T) != 1) = default;
// implicitly declares: friend constexpr bool operator==(X, X) requires (sizeof(T) != 1) = default;
[[nodiscard]] virtual std::strong_ordering operator<=>(const X&) const = default;
// implicitly declares: [[nodiscard]] virtual bool operator==(const X&) const = default;
};
— *end example*]

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.

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 usable ([class.compare.default]).

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.

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

- If a <=> b is usable ([class.compare.default]) and can be explicitly converted to R using static_cast, static_cast<R>(a <=> b).
- Otherwise, if overload resolution for a <=> b is performed and finds at least one viable candidate, the synthesized three-way comparison is not defined.
- Otherwise, if R is not a comparison category type, or either the expression a == b or the expression a < b is not usable, 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::equivalent : a < b ? weak_ordering::less : weak_ordering::greater
- Otherwise (when R is partial_ordering), a == b ? partial_ordering::equivalent : a < b ? partial_ordering::less : b < a ? partial_ordering::greater : partial_ordering::unordered

Let R be the declared return type of
a defaulted three-way comparison operator function, and
let be the elements of
the expanded list of subobjects for
an object x of type C.

- The operator function is defined as deleted if that expression is not usable or if is not a comparison category type ([cmp.categories.pre]) for any i.

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 of type R
between and
yields a result value where ,
contextually converted to bool, yields true;
V is a copy of .

The *common comparison type* U
of a possibly-empty list of n comparison category types
, , …,
is defined as follows:

A defaulted operator function ([over.binary])
for a secondary comparison 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 candidate, or
- the candidate selected by overload resolution is not a rewritten candidate.