Comparison operator functions can be explicitly defaulted to request the compiler to generate the corresponding default comparison for a class.
[edit] DefinitionA defaulted comparison operator function is a non-template comparison operator function (i.e. <=>
, ==
, !=
, <
, >
, <=
, or >=
) satisfying all following conditions:
C
.C
or in a context where C
is complete.C
, where the implicit object parameter (if any) is considered to be the first parameter.Such a comparison operator function is termed a defaulted comparison operator function for class C
.
struct X { bool operator==(const X&) const = default; // OK bool operator==(const X&) = default; // Error: the implicit object // parameter type is X& bool operator==(this X, X) = default; // OK }; struct Y { friend bool operator==(Y, Y) = default; // OK friend bool operator==(Y, const Y&) = default; // Error: different parameter types }; bool operator==(const Y&, const Y&) = default; // Error: not a friend of Y
Name lookups and access checks in the implicit definition of a comparison operator function are performed from a context equivalent to its function body. A definition of a comparison operator function as defaulted that appears in a class must be the first declaration of that function.
[edit] Default comparison orderGiven a class C
, a subobject list is formed by the following subjects in order:
C
, in declaration order.C
, in declaration order.For any object x of type C
, in the following descriptions:
struct S {}; struct T : S { int arr[2][2]; } t; // The subobject list for âtâ consists of the following 5 subobjects in order: // (S)t â t[0][0] â t[0][1] â t[1][0] â t[1][1][edit] Three-way comparison
An operator<=> for a class type can be defined as defaulted with any return type.
[edit] Comparison category typesThere are three comparison category types:
[edit] Synthesized three-way comparisonThe synthesized three-way comparison of type T
between glvalues a and b of the same type is defined as follows:
T
using static_cast
, the synthesized comparison is static_cast<T>(a <=> b).T
is not a comparison category type.T
is std::strong_ordering, the synthesized comparison isa == b ? std::strong_ordering::equal : a < b ? std::strong_ordering::less : std::strong_ordering::greater
T
is std::weak_ordering, the synthesized comparison isa == b ? std::weak_ordering::equivalent : a < b ? std::weak_ordering::less : std::weak_ordering::greater
T
is std::partial_ordering), the synthesized comparison isa == b ? std::partial_ordering::equivalent : a < b ? std::partial_ordering::less : b < a ? std::partial_ordering::greater : std::partial_ordering::unordered[edit] Placeholder return type
If the declared return type of a defaulted three-way comparison operator function (operator<=>) for a class type C
is auto, the return type is deduced from the return types of the three-way comparisons between the corresponding subobjects of an object x of type C
.
For each subobject x_i in the (expanded) subobject list for x:
R_i
, if R_i
is not a comparison category type, the defaulted operator<=> is defined as deleted.If the defaulted operator<=> is not defined as deleted, its return type is deduced as std::common_comparison_category_t<R_1, R_2, ..., R_n>.
[edit] Non-placeholder return typeIf the declared return type of the defaulted operator<=> is not auto, it cannot contain any placeholder type (e.g. decltype(auto)).
If there is a subobject x_i in the (expanded) subobject list for x such that the synthesized three-way comparison of the declared return type between x_i and x_i is not defined, the defaulted operator<=> is defined as deleted.
[edit] Comparison resultLet x and y be the parameters of a defaulted operator<=>, denote each subobject in the (expanded) subobject list for x and y as x_i and y_i respectively. The default three-way comparison between x and y is performed by comparing corresponding subobjects x_i and y_i with increasing i order.
Let R
be the (possibly-deduced) return type, the comparison result between x_i and y_i is the result of the synthesized three-way comparison of type R
between x_i and y_i.
#include <compare> #include <iostream> #include <set> struct Point { int x; int y; auto operator<=>(const Point&) const = default; /* non-comparison functions */ }; int main() { Point pt1{1, 1}, pt2{1, 2}; std::set<Point> s; // OK s.insert(pt1); // OK // two-way comparison operator functions are not required to be explicitly defined: // operator== is implicitly declared (see below) // the overload resolutions of other candidates will select rewritten candidates std::cout << std::boolalpha << (pt1 == pt2) << ' ' // false << (pt1 != pt2) << ' ' // true << (pt1 < pt2) << ' ' // true << (pt1 <= pt2) << ' ' // true << (pt1 > pt2) << ' ' // false << (pt1 >= pt2) << ' '; // false }[edit] Equality comparison [edit] Explicit declaration
An operator== for a class type can be defined as defaulted with return type bool.
Given a class C
and an object x of type C
, if there is a subobject x_i in the (expanded) subobject list for x such that the overload resolution for x_i == x_i does not result in a usable candidate, the defaulted operator== is defined as deleted.
Let x and y be the parameters of a defaulted operator==, denote each subobject in the (expanded) subobject list for x and y as x_i and y_i respectively. The default equality comparison between x and y is performed by comparing corresponding subobjects x_i and y_i with increasing i order.
The comparison result between x_i and y_i is the result of x_i == y_i.
#include <iostream> struct Point { int x; int y; bool operator==(const Point&) const = default; /* non-comparison functions */ }; int main() { Point pt1{3, 5}, pt2{2, 5}; std::cout << std::boolalpha << (pt1 != pt2) << '\n' // true << (pt1 == pt1) << '\n'; // true struct [[maybe_unused]] { int x{}, y{}; } p, q; // if (p == q) {} // Error: operator== is not defined }[edit] Implicit declaration
If a class C
does not explicitly declare any member or friend named operator==, an ==
operator function is declared implicitly for each operator<=> defined as defaulted. Each implicity-declared operator== have the same access and function definition and in the same class scope as the respective defaulted operator<=>, with the following changes:
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; };[edit] Secondary comparison
A secondary comparison operator function (!=
, <
, >
, <=
, or >=
) for a class type can be defined as defaulted with return type bool.
Let @
be one of the five secondary comparison operators, for each defaulted operator@ with parameters x and y, up to two overloads resolutions are performed (not considering the defaulted operator@ as a candidate) to determine whether it is defined as deleted.
If is x @ y cannot be implicitly converted to bool, the defaulted operator@ is defined as deleted.
If the defaulted operator@ is not defined as deleted, it yields x @ y.
struct HasNoRelational {}; struct C { friend HasNoRelational operator<=>(const C&, const C&); bool operator<(const C&) const = default; // OK, function is defaulted };[edit] Keywords [edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR Applied to Behavior as published Correct behavior CWG 2539 C++20 the synthesized three-way comparison would chooseRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4