7 Expressions [expr]

7.6 Compound expressions [expr.compound]

7.6.8 Three-way comparison operator [expr.spaceship]

The three-way comparison operator groups left-to-right.
compare-expression:
	shift-expression
	compare-expression <=> shift-expression
The expression p <=> q is a prvalue indicating whether p is less than, equal to, greater than, or incomparable with q.
If one of the operands is of type bool and the other is not, the program is ill-formed.
If both operands have arithmetic types, or one operand has integral type and the other operand has unscoped enumeration type, the usual arithmetic conversions are applied to the operands.
Then:
  • If a narrowing conversion is required, other than from an integral type to a floating point type, the program is ill-formed.
  • Otherwise, if the operands have integral type, the result is of type std​::​strong_­ordering.
    The result is std​::​strong_­ordering​::​equal if both operands are arithmetically equal, std​::​strong_­ordering​::​less if the first operand is arithmetically less than the second operand, and std​::​strong_­ordering​::​greater otherwise.
  • Otherwise, the operands have floating-point type, and the result is of type std​::​partial_­ordering.
    The expression a <=> b yields std​::​partial_­ordering​::​less if a is less than b, std​::​partial_­ordering​::​greater if a is greater than b, std​::​partial_­ordering​::​equivalent if a is equivalent to b, and std​::​partial_­ordering​::​unordered otherwise.
If both operands have the same enumeration type E, the operator yields the result of converting the operands to the underlying type of E and applying <=> to the converted operands.
If at least one of the operands is of pointer type, array-to-pointer conversions, pointer conversions, function pointer conversions, and qualification conversions are performed on both operands to bring them to their composite pointer type.
If at least one of the operands is of pointer-to-member type, pointer-to-member conversions and qualification conversions are performed on both operands to bring them to their composite pointer type.
If both operands are null pointer constants, but not both of integer type, pointer conversions are performed on both operands to bring them to their composite pointer type.
In all cases, after the conversions, the operands shall have the same type.
[Note
:
If both of the operands are arrays, array-to-pointer conversions are not applied.
end note
]
If the composite pointer type is a function pointer type, a pointer-to-member type, or std​::​nullptr_­t, the result is of type std​::​strong_­equality; the result is std​::​strong_­equality​::​equal if the (possibly converted) operands compare equal ([expr.eq]) and std​::​strong_­equality​::​nonequal if they compare unequal, otherwise the result of the operator is unspecified.
If the composite pointer type is an object pointer type, p <=> q is of type std​::​strong_­ordering.
If two pointer operands p and q compare equal ([expr.eq]), p <=> q yields std​::​strong_­ordering​::​equal; if p and q compare unequal, p <=> q yields std​::​strong_­ordering​::​less if q compares greater than p and std​::​strong_­ordering​::​greater if p compares greater than q ([expr.rel]).
Otherwise, the result is unspecified.
Otherwise, the program is ill-formed.
The five comparison category types (the types std​::​strong_­ordering, std​::​strong_­equality, std​::​weak_­ordering, std​::​weak_­equality, and std​::​partial_­ordering) are not predefined; if the header <compare> is not included prior to a use of such a class type – even an implicit use in which the type is not named (e.g., via the auto specifier in a defaulted three-way comparison or use of the built-in operator) – the program is ill-formed.