17 Language support library [language.support]

17.11 Comparisons [cmp]

17.11.1 Header <compare> synopsis [compare.syn]

The header <compare> specifies types, objects, and functions for use primarily in connection with the three-way comparison operator.
namespace std {
  // [cmp.categories], comparison category types
  class weak_equality;
  class strong_equality;
  class partial_ordering;
  class weak_ordering;
  class strong_ordering;

  // named comparison functions
  constexpr bool is_eq  (weak_equality cmp) noexcept    { return cmp == 0; }
  constexpr bool is_neq (weak_equality cmp) noexcept    { return cmp != 0; }
  constexpr bool is_lt  (partial_ordering cmp) noexcept { return cmp < 0; }
  constexpr bool is_lteq(partial_ordering cmp) noexcept { return cmp <= 0; }
  constexpr bool is_gt  (partial_ordering cmp) noexcept { return cmp > 0; }
  constexpr bool is_gteq(partial_ordering cmp) noexcept { return cmp >= 0; }

  // [cmp.common], common comparison category type
  template<class... Ts>
  struct common_comparison_category {
    using type = see below;
  };
  template<class... Ts>
    using common_comparison_category_t = typename common_comparison_category<Ts...>::type;

  // [cmp.concept], concept three_­way_­comparable
  template<class T, class Cat = partial_ordering>
    concept three_way_comparable = see below;
  template<class T, class U, class Cat = partial_ordering>
    concept three_way_comparable_with = see below;

  // [cmp.result], result of three-way comparison
  template<class T, class U = T> struct compare_three_way_result;

  template<class T, class U = T>
    using compare_three_way_result_t = typename compare_three_way_result<T, U>::type;

  // [cmp.object], class compare_­three_­way
  struct compare_three_way;

  // [cmp.alg], comparison algorithms
  inline namespace unspecified {
    inline constexpr unspecified strong_order = unspecified;
    inline constexpr unspecified weak_order = unspecified;
    inline constexpr unspecified partial_order = unspecified;
    inline constexpr unspecified compare_strong_order_fallback = unspecified;
    inline constexpr unspecified compare_weak_order_fallback = unspecified;
    inline constexpr unspecified compare_partial_order_fallback = unspecified;
  }
}

17.11.2 Comparison category types [cmp.categories]

17.11.2.1 Preamble [cmp.categories.pre]

The types weak_­equality, strong_­equality, partial_­ordering, weak_­ordering, and strong_­ordering are collectively termed the comparison category types.
Each is specified in terms of an exposition-only data member named value whose value typically corresponds to that of an enumerator from one of the following exposition-only enumerations:
enum class eq { equal = 0, equivalent = equal,
                nonequal = 1, nonequivalent = nonequal };   // exposition only
enum class ord { less = -1, greater = 1 };                  // exposition only
enum class ncmp { unordered = -127 };                       // exposition only
Note
:
The types strong_­ordering and weak_­equality correspond, respectively, to the terms total ordering and equivalence in mathematics.
— end note
 ]
The relational and equality operators for the comparison category types are specified with an anonymous parameter of unspecified type.
This type shall be selected by the implementation such that these parameters can accept literal 0 as a corresponding argument.
Example
:
nullptr_­t meets this requirement.
— end example
 ]
In this context, the behavior of a program that supplies an argument other than a literal 0 is undefined.
For the purposes of this subclause, substitutability is the property that f(a) == f(b) is true whenever a == b is true, where f denotes a function that reads only comparison-salient state that is accessible via the argument's public const members.

17.11.2.2 Class weak_­equality [cmp.weakeq]

The weak_­equality type is typically used as the result type of a three-way comparison operator that (a) admits only equality and inequality comparisons, and (b) does not imply substitutability.
namespace std {
  class weak_equality {
    int value;  // exposition only

    // exposition-only constructor
    constexpr explicit weak_equality(eq v) noexcept : value(int(v)) {}  // exposition only

  public:
    // valid values
    static const weak_equality equivalent;
    static const weak_equality nonequivalent;

    // comparisons
    friend constexpr bool operator==(weak_equality v, unspecified) noexcept;
    friend constexpr bool operator==(weak_equality v, weak_equality w) noexcept = default;
    friend constexpr weak_equality operator<=>(weak_equality v, unspecified) noexcept;
    friend constexpr weak_equality operator<=>(unspecified, weak_equality v) noexcept;
  };

  // valid values' definitions
  inline constexpr weak_equality weak_equality::equivalent(eq::equivalent);
  inline constexpr weak_equality weak_equality::nonequivalent(eq::nonequivalent);
}
constexpr bool operator==(weak_equality v, unspecified) noexcept;
Returns: v.value == 0.
constexpr weak_equality operator<=>(weak_equality v, unspecified) noexcept; constexpr weak_equality operator<=>(unspecified, weak_equality v) noexcept;
Returns: v.

17.11.2.3 Class strong_­equality [cmp.strongeq]

The strong_­equality type is typically used as the result type of a three-way comparison operator that (a) admits only equality and inequality comparisons, and (b) does imply substitutability.
namespace std {
  class strong_equality {
    int value;  // exposition only

    // exposition-only constructor
    constexpr explicit strong_equality(eq v) noexcept : value(int(v)) {}    // exposition only

  public:
    // valid values
    static const strong_equality equal;
    static const strong_equality nonequal;
    static const strong_equality equivalent;
    static const strong_equality nonequivalent;

    // conversion
    constexpr operator weak_equality() const noexcept;

    // comparisons
    friend constexpr bool operator==(strong_equality v, unspecified) noexcept;
    friend constexpr bool operator==(strong_equality v, strong_equality w) noexcept = default;
    friend constexpr strong_equality operator<=>(strong_equality v, unspecified) noexcept;
    friend constexpr strong_equality operator<=>(unspecified, strong_equality v) noexcept;
  };

  // valid values' definitions
  inline constexpr strong_equality strong_equality::equal(eq::equal);
  inline constexpr strong_equality strong_equality::nonequal(eq::nonequal);
  inline constexpr strong_equality strong_equality::equivalent(eq::equivalent);
  inline constexpr strong_equality strong_equality::nonequivalent(eq::nonequivalent);
}
constexpr operator weak_equality() const noexcept;
Returns: value == 0 ? weak_­equality​::​equivalent : weak_­equality​::​nonequivalent.
constexpr bool operator==(strong_equality v, unspecified) noexcept;
Returns: v.value == 0.
constexpr strong_equality operator<=>(strong_equality v, unspecified) noexcept; constexpr strong_equality operator<=>(unspecified, strong_equality v) noexcept;
Returns: v.

17.11.2.4 Class partial_­ordering [cmp.partialord]

The partial_­ordering type is typically used as the result type of a three-way comparison operator that (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), (b) does not imply substitutability, and (c) permits two values to be incomparable.216
namespace std {
  class partial_ordering {
    int value;          // exposition only
    bool is_ordered;    // exposition only

    // exposition-only constructors
    constexpr explicit
      partial_ordering(eq v) noexcept : value(int(v)), is_ordered(true) {}      // exposition only
    constexpr explicit
      partial_ordering(ord v) noexcept : value(int(v)), is_ordered(true) {}     // exposition only
    constexpr explicit
      partial_ordering(ncmp v) noexcept : value(int(v)), is_ordered(false) {}   // exposition only

  public:
    // valid values
    static const partial_ordering less;
    static const partial_ordering equivalent;
    static const partial_ordering greater;
    static const partial_ordering unordered;

    // conversion
    constexpr operator weak_equality() const noexcept;

    // comparisons
    friend constexpr bool operator==(partial_ordering v, unspecified) noexcept;
    friend constexpr bool operator==(partial_ordering v, partial_ordering w) noexcept = default;
    friend constexpr bool operator< (partial_ordering v, unspecified) noexcept;
    friend constexpr bool operator> (partial_ordering v, unspecified) noexcept;
    friend constexpr bool operator<=(partial_ordering v, unspecified) noexcept;
    friend constexpr bool operator>=(partial_ordering v, unspecified) noexcept;
    friend constexpr bool operator< (unspecified, partial_ordering v) noexcept;
    friend constexpr bool operator> (unspecified, partial_ordering v) noexcept;
    friend constexpr bool operator<=(unspecified, partial_ordering v) noexcept;
    friend constexpr bool operator>=(unspecified, partial_ordering v) noexcept;
    friend constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
    friend constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
  };

  // valid values' definitions
  inline constexpr partial_ordering partial_ordering::less(ord::less);
  inline constexpr partial_ordering partial_ordering::equivalent(eq::equivalent);
  inline constexpr partial_ordering partial_ordering::greater(ord::greater);
  inline constexpr partial_ordering partial_ordering::unordered(ncmp::unordered);
}
constexpr operator weak_equality() const noexcept;
Returns: value == 0 ? weak_­equality​::​equivalent : weak_­equality​::​nonequivalent.
Note
:
The result is independent of the is_­ordered member.
— end note
 ]
constexpr bool operator==(partial_ordering v, unspecified) noexcept; constexpr bool operator< (partial_ordering v, unspecified) noexcept; constexpr bool operator> (partial_ordering v, unspecified) noexcept; constexpr bool operator<=(partial_ordering v, unspecified) noexcept; constexpr bool operator>=(partial_ordering v, unspecified) noexcept;
Returns: For operator@, v.is_­ordered && v.value @ 0.
constexpr bool operator< (unspecified, partial_ordering v) noexcept; constexpr bool operator> (unspecified, partial_ordering v) noexcept; constexpr bool operator<=(unspecified, partial_ordering v) noexcept; constexpr bool operator>=(unspecified, partial_ordering v) noexcept;
Returns: For operator@, v.is_­ordered && 0 @ v.value.
constexpr partial_ordering operator<=>(partial_ordering v, unspecified) noexcept;
Returns: v.
constexpr partial_ordering operator<=>(unspecified, partial_ordering v) noexcept;
Returns: v < 0 ? partial_­ordering​::​greater : v > 0 ? partial_­ordering​::​less : v.
That is, a < b, a == b, and a > b might all be false.

17.11.2.5 Class weak_­ordering [cmp.weakord]

The weak_­ordering type is typically used as the result type of a three-way comparison operator that (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), and (b) does not imply substitutability.
namespace std {
  class weak_ordering {
    int value;  // exposition only

    // exposition-only constructors
    constexpr explicit weak_ordering(eq v) noexcept : value(int(v)) {}  // exposition only
    constexpr explicit weak_ordering(ord v) noexcept : value(int(v)) {} // exposition only

  public:
    // valid values
    static const weak_ordering less;
    static const weak_ordering equivalent;
    static const weak_ordering greater;

    // conversions
    constexpr operator weak_equality() const noexcept;
    constexpr operator partial_ordering() const noexcept;

    // comparisons
    friend constexpr bool operator==(weak_ordering v, unspecified) noexcept;
    friend constexpr bool operator==(weak_ordering v, weak_ordering w) noexcept = default;
    friend constexpr bool operator< (weak_ordering v, unspecified) noexcept;
    friend constexpr bool operator> (weak_ordering v, unspecified) noexcept;
    friend constexpr bool operator<=(weak_ordering v, unspecified) noexcept;
    friend constexpr bool operator>=(weak_ordering v, unspecified) noexcept;
    friend constexpr bool operator< (unspecified, weak_ordering v) noexcept;
    friend constexpr bool operator> (unspecified, weak_ordering v) noexcept;
    friend constexpr bool operator<=(unspecified, weak_ordering v) noexcept;
    friend constexpr bool operator>=(unspecified, weak_ordering v) noexcept;
    friend constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
    friend constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
  };

  // valid values' definitions
  inline constexpr weak_ordering weak_ordering::less(ord::less);
  inline constexpr weak_ordering weak_ordering::equivalent(eq::equivalent);
  inline constexpr weak_ordering weak_ordering::greater(ord::greater);
}
constexpr operator weak_equality() const noexcept;
Returns: value == 0 ? weak_­equality​::​equivalent : weak_­equality​::​nonequivalent.
constexpr operator partial_ordering() const noexcept;
Returns:
value == 0 ? partial_ordering::equivalent :
value < 0  ? partial_ordering::less :
             partial_ordering::greater
constexpr bool operator==(weak_ordering v, unspecified) noexcept; constexpr bool operator< (weak_ordering v, unspecified) noexcept; constexpr bool operator> (weak_ordering v, unspecified) noexcept; constexpr bool operator<=(weak_ordering v, unspecified) noexcept; constexpr bool operator>=(weak_ordering v, unspecified) noexcept;
Returns: v.value @ 0 for operator@.
constexpr bool operator< (unspecified, weak_ordering v) noexcept; constexpr bool operator> (unspecified, weak_ordering v) noexcept; constexpr bool operator<=(unspecified, weak_ordering v) noexcept; constexpr bool operator>=(unspecified, weak_ordering v) noexcept;
Returns: 0 @ v.value for operator@.
constexpr weak_ordering operator<=>(weak_ordering v, unspecified) noexcept;
Returns: v.
constexpr weak_ordering operator<=>(unspecified, weak_ordering v) noexcept;
Returns: v < 0 ? weak_­ordering​::​greater : v > 0 ? weak_­ordering​::​less : v.

17.11.2.6 Class strong_­ordering [cmp.strongord]

The strong_­ordering type is typically used as the result type of a three-way comparison operator that (a) admits all of the six two-way comparison operators ([expr.rel], [expr.eq]), and (b) does imply substitutability.
namespace std {
  class strong_ordering {
    int value;  // exposition only

    // exposition-only constructors
    constexpr explicit strong_ordering(eq v) noexcept : value(int(v)) {}    // exposition only
    constexpr explicit strong_ordering(ord v) noexcept : value(int(v)) {}   // exposition only

  public:
    // valid values
    static const strong_ordering less;
    static const strong_ordering equal;
    static const strong_ordering equivalent;
    static const strong_ordering greater;

    // conversions
    constexpr operator weak_equality() const noexcept;
    constexpr operator strong_equality() const noexcept;
    constexpr operator partial_ordering() const noexcept;
    constexpr operator weak_ordering() const noexcept;

    // comparisons
    friend constexpr bool operator==(strong_ordering v, unspecified) noexcept;
    friend constexpr bool operator==(strong_ordering v, strong_ordering w) noexcept = default;
    friend constexpr bool operator< (strong_ordering v, unspecified) noexcept;
    friend constexpr bool operator> (strong_ordering v, unspecified) noexcept;
    friend constexpr bool operator<=(strong_ordering v, unspecified) noexcept;
    friend constexpr bool operator>=(strong_ordering v, unspecified) noexcept;
    friend constexpr bool operator< (unspecified, strong_ordering v) noexcept;
    friend constexpr bool operator> (unspecified, strong_ordering v) noexcept;
    friend constexpr bool operator<=(unspecified, strong_ordering v) noexcept;
    friend constexpr bool operator>=(unspecified, strong_ordering v) noexcept;
    friend constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
    friend constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
  };

  // valid values' definitions
  inline constexpr strong_ordering strong_ordering::less(ord::less);
  inline constexpr strong_ordering strong_ordering::equal(eq::equal);
  inline constexpr strong_ordering strong_ordering::equivalent(eq::equivalent);
  inline constexpr strong_ordering strong_ordering::greater(ord::greater);
}
constexpr operator weak_equality() const noexcept;
Returns: value == 0 ? weak_­equality​::​equivalent : weak_­equality​::​nonequivalent.
constexpr operator strong_equality() const noexcept;
Returns: value == 0 ? strong_­equality​::​equal : strong_­equality​::​nonequal.
constexpr operator partial_ordering() const noexcept;
Returns:
value == 0 ? partial_ordering::equivalent :
value < 0  ? partial_ordering::less :
             partial_ordering::greater
constexpr operator weak_ordering() const noexcept;
Returns:
value == 0 ? weak_ordering::equivalent :
value < 0  ? weak_ordering::less :
             weak_ordering::greater
constexpr bool operator==(strong_ordering v, unspecified) noexcept; constexpr bool operator< (strong_ordering v, unspecified) noexcept; constexpr bool operator> (strong_ordering v, unspecified) noexcept; constexpr bool operator<=(strong_ordering v, unspecified) noexcept; constexpr bool operator>=(strong_ordering v, unspecified) noexcept;
Returns: v.value @ 0 for operator@.
constexpr bool operator< (unspecified, strong_ordering v) noexcept; constexpr bool operator> (unspecified, strong_ordering v) noexcept; constexpr bool operator<=(unspecified, strong_ordering v) noexcept; constexpr bool operator>=(unspecified, strong_ordering v) noexcept;
Returns: 0 @ v.value for operator@.
constexpr strong_ordering operator<=>(strong_ordering v, unspecified) noexcept;
Returns: v.
constexpr strong_ordering operator<=>(unspecified, strong_ordering v) noexcept;
Returns: v < 0 ? strong_­ordering​::​greater : v > 0 ? strong_­ordering​::​less : v.

17.11.3 Class template common_­comparison_­category [cmp.common]

The type common_­comparison_­category provides an alias for the strongest comparison category to which all of the template arguments can be converted.
Note
:
A comparison category type is stronger than another if they are distinct types and an instance of the former can be converted to an instance of the latter.
— end note
 ]
template<class... Ts> struct common_comparison_category { using type = see below; };
Remarks: The member typedef-name type denotes the common comparison type ([class.spaceship]) of Ts..., the expanded parameter pack.
Note
:
This is well-defined even if the expansion is empty or includes a type that is not a comparison category type.
— end note
 ]

17.11.4 Concept three_­way_­comparable [cmp.concept]

template<class T, class Cat>
  concept compares-as =                 // exposition only
    same_as<common_comparison_category_t<T, Cat>, Cat>;

template<class T, class U>
  concept partially-ordered-with =      // exposition only
    requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
      { t <  u } -> boolean;
      { t >  u } -> boolean;
      { t <= u } -> boolean;
      { t >= u } -> boolean;
      { u <  t } -> boolean;
      { u >  t } -> boolean;
      { u <= t } -> boolean;
      { u >= t } -> boolean;
    };
Let t and u be lvalues of types const remove_­reference_­t<T> and const remove_­reference_­t<U>, respectively.
T and U model partially-ordered-with<T, U> only if:
  • t < u, t <= u, t > u, t >= u, u < t, u <= t, u > t, and u >= t have the same domain.
  • bool(t < u) == bool(u > t) is true,
  • bool(u < t) == bool(t > u) is true,
  • bool(t <= u) == bool(u >= t) is true, and
  • bool(u <= t) == bool(t >= u) is true.
template<class T, class Cat = partial_ordering>
  concept three_way_comparable =
    weakly-equality-comparable-with<T, T> &&
    (!convertible_to<Cat, partial_ordering> || partially-ordered-with<T, T>) &&
    requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b) {
      { a <=> b } -> compares-as<Cat>;
    };
Let a and b be lvalues of type const remove_­reference_­t<T>.
T and Cat model three_­way_­comparable<T, Cat> only if:
  • (a <=> b == 0) == bool(a == b) is true;
  • (a <=> b != 0) == bool(a != b) is true;
  • ((a <=> b) <=> 0) and (0 <=> (b <=> a)) are equal;
  • if Cat is convertible to strong_­equality, T models equality_­comparable ([concept.equalitycomparable]);
  • if Cat is convertible to partial_­ordering:
    • (a <=> b < 0) == bool(a < b) is true,
    • (a <=> b > 0) == bool(a > b) is true,
    • (a <=> b <= 0) == bool(a <= b) is true, and
    • (a <=> b >= 0) == bool(a >= b) is true; and
  • If Cat is convertible to strong_­ordering, T models totally_­ordered ([concept.totallyordered]).
template<class T, class U, class Cat = partial_ordering>
  concept three_way_comparable_with =
    weakly-equality-comparable-with<T, U> &&
    (!convertible_to<Cat, partial_ordering> || partially-ordered-with<T, U>) &&
    three_way_comparable<T, Cat> &&
    three_way_comparable<U, Cat> &&
    common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
    three_way_comparable<
      common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>, Cat> &&
    requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u) {
      { t <=> u } -> compares-as<Cat>;
      { u <=> t } -> compares-as<Cat>;
    };
Let t and u be lvalues of types const remove_­reference_­t<T> and const remove_­reference_­t<U>, respectively.
Let C be common_­reference_­t<const remove_­reference_­t<T>&, const remove_­reference_­t<U>&>.
T, U, and Cat model three_­way_­comparable_­with<T, U, Cat> only if:
  • t <=> u and u <=> t have the same domain;
  • ((t <=> u) <=> 0) and (0 <=> (u <=> t)) are equal;
  • (t <=> u == 0) == bool(t == u) is true;
  • (t <=> u != 0) == bool(t != u) is true;
  • Cat(t <=> u) == Cat(C(t) <=> C(u)) is true;
  • if Cat is convertible to strong_­equality, T and U model equality_­comparable_­with<T, U> ([concept.equalitycomparable]);
  • if Cat is convertible to partial_­ordering:
    • (t <=> u < 0) == bool(t < u) is true,
    • (t <=> u > 0) == bool(t > u) is true,
    • (t <=> u <= 0) == bool(t <= u) is true,
    • (t <=> u >= 0) == bool(t >= u) is true; and
  • if Cat is convertible to strong_­ordering, T and U model totally_­ordered_­with<T, U> ([concept.totallyordered]).

17.11.5 Result of three-way comparison [cmp.result]

The behavior of a program that adds specializations for the compare_­three_­way_­result template defined in this subclause is undefined.
For the compare_­three_­way_­result type trait applied to the types T and U, let t and u denote lvalues of types const remove_­reference_­t<T> and const remove_­reference_­t<U>, respectively.
If the expression t <=> u is well-formed when treated as an unevaluated operand ([expr.context]), the member typedef-name type denotes the type decltype(t <=> u).
Otherwise, there is no member type.

17.11.6 Class compare_­three_­way [cmp.object]

In this subclause, BUILTIN-PTR-THREE-WAY(T, U) for types T and U is a boolean constant expression.
BUILTIN-PTR-THREE-WAY(T, U) is true if and only if <=> in the expression
declval<T>() <=> declval<U>()
resolves to a built-in operator comparing pointers.
struct compare_three_way {
  template<class T, class U>
    requires three_way_comparable_with<T, U> || BUILTIN-PTR-THREE-WAY(T, U)
  constexpr auto operator()(T&& t, U&& u) const;

  using is_transparent = unspecified;
};
In addition to being available via inclusion of the <compare> header, the class compare_­three_­way is available when the header <functional> is included.
template<class T, class U> requires three_way_comparable_with<T, U> || BUILTIN-PTR-THREE-WAY(T, U) constexpr auto operator()(T&& t, U&& u) const;
Expects: If the expression std​::​forward<T>(t) <=> std​::​forward<U>(u) results in a call to a built-in operator <=> comparing pointers of type P, the conversion sequences from both T and U to P are equality-preserving ([concepts.equality]).
Effects:
  • If the expression std​::​forward<T>(t) <=> std​::​forward<U>(u) results in a call to a built-in operator <=> comparing pointers of type P, returns strong_­ordering​::​less if (the converted value of) t precedes u in the implementation-defined strict total order ([range.cmp]) over pointers of type P, strong_­ordering​::​greater if u precedes t, and otherwise strong_­ordering​::​equal.
  • Otherwise, equivalent to: return std​::​forward<T>(t) <=> std​::​forward<U>(u);

17.11.7 Comparison algorithms [cmp.alg]

The name strong_­order denotes a customization point object ([customization.point.object]).
The expression strong_­order(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to the following:
  • If the decayed types of E and F differ, strong_­order(E, F) is ill-formed.
  • Otherwise, strong_­ordering(strong_­order(E, F)) if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of std​::​strong_­order.
  • Otherwise, if the decayed type T of E is a floating-point type, yields a value of type strong_­ordering that is consistent with the ordering observed by T's comparison operators, and if numeric_­limits<T>​::​is_­iec559 is true, is additionally consistent with the totalOrder operation as specified in ISO/IEC/IEEE 60599.
  • Otherwise, strong_­ordering(E <=> F) if it is a well-formed expression.
  • Otherwise, strong_­order(E, F) is ill-formed.
    Note
    : This case can result in substitution failure when strong_­order(E, F) appears in the immediate context of a template instantiation. — end note
     ]
The name weak_­order denotes a customization point object ([customization.point.object]).
The expression weak_­order(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to the following:
  • If the decayed types of E and F differ, weak_­order(E, F) is ill-formed.
  • Otherwise, weak_­ordering(weak_­order(E, F)) if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of std​::​weak_­order.
  • Otherwise, if the decayed type T of E is a floating-point type, yields a value of type weak_­ordering that is consistent with the ordering observed by T's comparison operators and strong_­order, and if numeric_­limits<T>​::​is_­iec559 is true, is additionally consistent with the following equivalence classes, ordered from lesser to greater:
  • Otherwise, weak_­ordering(E <=> F) if it is a well-formed expression.
  • Otherwise, weak_­ordering(strong_­order(E, F)) if it is a well-formed expression.
  • Otherwise, weak_­order(E, F) is ill-formed.
    Note
    : This case can result in substitution failure when std​::​weak_­order(E, F) appears in the immediate context of a template instantiation. — end note
     ]
The name partial_­order denotes a customization point object ([customization.point.object]).
The expression partial_­order(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to the following:
  • If the decayed types of E and F differ, partial_­order(E, F) is ill-formed.
  • Otherwise, partial_­ordering(partial_­order(E, F)) if it is a well-formed expression with overload resolution performed in a context that does not include a declaration of std​::​partial_­order.
  • Otherwise, partial_­ordering(E <=> F) if it is a well-formed expression.
  • Otherwise, partial_­ordering(weak_­order(E, F)) if it is a well-formed expression.
  • Otherwise, partial_­order(E, F) is ill-formed.
    Note
    : This case can result in substitution failure when std​::​partial_­order(E, F) appears in the immediate context of a template instantiation. — end note
     ]
The name compare_­strong_­order_­fallback denotes a customization point object ([customization.point.object]).
The expression compare_­strong_­order_­fallback(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to:
  • If the decayed types of E and F differ, compare_­strong_­order_­fallback(E, F) is ill-formed.
  • Otherwise, strong_­order(E, F) if it is a well-formed expression.
  • Otherwise, if the expressions E == F and E < F are both well-formed and convertible to bool,
    E == F ? strong_ordering::equal :
    E < F  ? strong_ordering::less :
             strong_ordering::greater
    
    except that E and F are evaluated only once.
  • Otherwise, compare_­strong_­order_­fallback(E, F) is ill-formed.
The name compare_­weak_­order_­fallback denotes a customization point object ([customization.point.object]).
The expression compare_­weak_­order_­fallback(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to:
  • If the decayed types of E and F differ, compare_­weak_­order_­fallback(E, F) is ill-formed.
  • Otherwise, weak_­order(E, F) if it is a well-formed expression.
  • Otherwise, if the expressions E == F and E < F are both well-formed and convertible to bool,
    E == F ? weak_ordering::equal :
    E < F  ? weak_ordering::less :
             weak_ordering::greater
    
    except that E and F are evaluated only once.
  • Otherwise, compare_­weak_­order_­fallback(E, F) is ill-formed.
The name compare_­partial_­order_­fallback denotes a customization point object ([customization.point.object]).
The expression compare_­partial_­order_­fallback(E, F) for some subexpressions E and F is expression-equivalent ([defns.expression-equivalent]) to:
  • If the decayed types of E and F differ, compare_­partial_­order_­fallback(E, F) is ill-formed.
  • Otherwise, partial_­order(E, F) if it is a well-formed expression.
  • Otherwise, if the expressions E == F and E < F are both well-formed and convertible to bool,
    E == F ? partial_ordering::equivalent :
    E < F  ? partial_ordering::less :
    F < E  ? partial_ordering::greater :
             partial_ordering::unordered
    
    except that E and F are evaluated only once.
  • Otherwise, compare_­partial_­order_­fallback(E, F) is ill-formed.