Comparison operators
Compares the arguments.
Operator name | Syntax | Overloadable | Prototype examples (for class T) | |
---|---|---|---|---|
As member function | As free (namespace) function | |||
equal to | a == b
|
Yes | bool T::operator ==(const T2 &b) const; | bool operator ==(const T &a, const T2 &b); |
not equal to | a!= b
|
Yes | bool T::operator !=(const T2 &b) const; | bool operator !=(const T &a, const T2 &b); |
less than | a < b
|
Yes | bool T::operator <(const T2 &b) const; | bool operator <(const T &a, const T2 &b); |
greater than | a > b
|
Yes | bool T::operator >(const T2 &b) const; | bool operator >(const T &a, const T2 &b); |
less than or equal to | a <= b
|
Yes | bool T::operator <=(const T2 &b) const; | bool operator <=(const T &a, const T2 &b); |
greater than or equal to | a >= b
|
Yes | bool T::operator >=(const T2 &b) const; | bool operator >=(const T &a, const T2 &b); |
three-way comparison (C++20) | a <=> b
|
Yes | /*see description*/ T::operator <=>(const T2 &b) const; | /*see description*/ operator <=>(const T &a, const T2 &b); |
|
Two-way comparison
The two-way comparison operator expressions have the form
lhs < rhs
|
(1) | ||||||||
lhs > rhs
|
(2) | ||||||||
lhs <= rhs
|
(3) | ||||||||
lhs >= rhs
|
(4) | ||||||||
lhs == rhs
|
(5) | ||||||||
lhs != rhs
|
(6) | ||||||||
true
if lhs is less than rhs, false
otherwise.true
if lhs is greater than rhs, false
otherwise.true
if lhs is less than or equal to rhs, false
otherwise.true
if lhs is greater than or equal to rhs, false
otherwise.true
if lhs is equal to rhs, false
otherwise.true
if lhs is not equal to rhs, false
otherwise.In all cases, for the built-in operators, lhs and rhs must have either
- arithmetic or enumeration type (see arithmetic comparison operators below)
- pointer type (see pointer comparison operators below)
after the application of the lvalue-to-rvalue, array-to-pointer and function-to-pointer standard conversions. The comparison is deprecated if both operands have array type prior to the application of these conversions. (since C++20)
In any case, the result is a bool
prvalue.
Arithmetic comparison operators
If the operands has arithmetic or enumeration type (scoped or unscoped), usual arithmetic conversions are performed on both operands following the rules for arithmetic operators. The values are compared after conversions:
Example
#include <iostream> int main() { std::cout << std::boolalpha; int n = -1; int n2 = 1; std::cout << " -1 == 1? " << (n == n2) << '\n' << "Comparing two signed values:\n" << " -1 < 1? " << (n < n2) << '\n' << " -1 > 1? " << (n > n2) << '\n'; unsigned int u = 1; std::cout << "Comparing signed and unsigned:\n" << " -1 < 1? " << (n < u) << '\n' << " -1 > 1? " << (n > u) << '\n'; unsigned char uc = 1; std::cout << "Comparing signed and smaller unsigned:\n" << " -1 < 1? " << (n < uc) << '\n' << " -1 > 1? " << (n > uc) << '\n'; }
Output:
-1 == 1? false Comparing two signed values: -1 < 1? true -1 > 1? false Comparing signed and unsigned: -1 < 1? false -1 > 1? true Comparing signed and smaller unsigned: -1 < 1? true -1 > 1? false
Pointer comparison operators
Comparison operators can be used to compare two pointers (or pointers-to-members, for operator== and operator!= only), or a pointer to member (since C++14) and a null pointer constant, or two null pointer constants (but only as long as at least one of them is std::nullptr_t: comparison of NULL and NULL follows arithmetic comparison rules) (until C++14).
First, Pointer conversions (pointer to member conversions if the arguments are pointers to members), function pointer conversions, (since C++17) and qualification conversions are applied to both operands to obtain the composite pointer type, as follows
T
for some type T
, where T
is an object type or void, the composite type is "pointer to cv12 void", where cv12 is the union of cv1 and cv2
4) If both operands are pointers to the same type, with different cv-qualification, the composite is pointer to the same type with cv-qualification that is a union of the cv-qualifications of the arguments.
|
(until C++14) |
4) If the types of the operands are P1, a pointer to (possibly cv-qualified) T1, and P2, a pointer to (possibly cv-qualified) T2, and if T1 is the same as T2 or is a base class of T2, then the composite pointer type is the cv-combined type of P1 and P2. Otherwise, if T2 is a base class of T1, then the composite pointer type is the cv-combined type of P2 and P1.
5) If the types of the operands are MP1, pointer to member of T1 of type (possibly cv-qualified) U1 and MP2, pointer to member of T2 of type (possibly cv-qualified) U2, and if T1 is the same as or derived from T2, then the composite pointer type is the cv-combined type of MP1 and MP2. Otherwise, if T2 is derived from T1, then the composite pointer type is the cv-combined type of MP2 and MP1.
6) if the types of the operands P1 and P2 are multi-level mixed pointer and pointer to member types with the same number of levels that only differ by cv-qualifications at any of the levels, the composite pointer type is the cv-combined type of P1 and P2
In the definition above, cv-combined type of two pointer types P1 and P2 is a type P3 that has the same number of levels and type at every level as P1, except that cv-qualifications at every level are set as follows: a) at every level other than top level, the union of the cv-qualifications of P1 and P2 at that level
b) if the resulting cv-qualification at any level is different from P1's or P2's cv-qualification at the same level, then const is added to every level between the top level and this one.
For example, the composite pointer type of void* and const int* is const void*. The composite pointer type of int** and const int** is const int* const*. Note that until C++14, int** and const int** could not be compared. |
(since C++14) |
In addition to the above, the composite pointer type between pointer to function and pointer to noexcept function (as long as the function type is the same) is pointer to function. |
(since C++17) |
Note that this implies that any pointer can be compared with void*.
The result of comparing two pointers to objects (after conversions) is defined as follows:
&obj+1
compares greater than &obj
(since C++17)The result of equality comparison of two pointers (after conversions) is defined as follows:
The result of comparing two pointers to members (after conversions) is defined as follows:
If a pointer p
compare equal to pointer q
, p<=q
and p>=q
both yield true
and p<q
and p>q
both yield false
.
If a pointer p
compares greater than a pointer q
, then p>=q
, p>q
, q<=p
, and q<p
all yield true
and p<=q
, p<q
, q>=p
, and q>p
all yield false
.
If two pointers are not specified to compare greater or compare equal, the result of the comparison is unspecified. The result may be nondeterministic, and need not be consistent even for multiple evaluations of the same expression with the same operands in the same execution of the program:
int x, y; bool f(int* p, int* q) { return p < q; } assert(f(&x, &y) == f(&x, &y)); // may fire in a conforming implementation
In overload resolution against user-defined operators, for every pair of promoted arithmetic types L
and R
, including enumeration types, the following function signatures participate in overload resolution:
bool operator<(L, R); |
||
bool operator>(L, R); |
||
bool operator<=(L, R); |
||
bool operator>=(L, R); |
||
bool operator==(L, R); |
||
bool operator!=(L, R); |
||
For every type P
which is either pointer to object or pointer to function or std::nullptr_t (until C++14), the following function signatures participate in overload resolution:
bool operator<(P, P); |
||
bool operator>(P, P); |
||
bool operator<=(P, P); |
||
bool operator>=(P, P); |
||
bool operator==(P, P); |
||
bool operator!=(P, P); |
||
For every type MP
that is a pointer to member object or pointer to member function or std::nullptr_t, the following function signatures participate in overload resolution:
bool operator==(MP, MP); |
||
bool operator!=(MP, MP); |
||
Example
#include <iostream> struct Foo { int n1; int n2; }; union Union { int n; double d; }; int main() { std::cout << std::boolalpha; char a[4] = "abc"; char* p1 = &a[1]; char* p2 = &a[2]; std::cout << "Pointers to array elements: p1 == p2 " << (p1 == p2) << ", p1 < p2 " << (p1 < p2) << '\n'; Foo f; int* p3 = &f.n1; int* p4 = &f.n2; std::cout << "Pointers to members of a class: p3 == p4 " << (p3 == p4) << ", p3 < p4 " << (p3 < p4) << '\n'; Union u; int* p5 = &u.n; double* p6 = &u.d; std::cout << "Pointers to members of a union: p5 == (void*)p6 " << (p5 == (void*)p6) << ", p5 < p6 " << (p5 < (void*)p6) << '\n'; }
Output:
Pointers to array elements: p1 == p2 false, p1 < p2 true Pointers to members of a class: p3 == p4 false, p3 < p4 true Pointers to members of a union: p5 == (void*)p6 true, p5 < p6 false
Notes
Because these operators group left-to-right, the expression a<b<c is parsed (a<b)<c, and not a<(b<c) or (a<b)&&(b<c).
A common requirement for user-defined operator< is strict weak ordering. In particular, this is required by the standard algorithms and containers that work with Compare types: std::sort, std::max_element, std::map, etc.
Although the results of comparing pointers of random origin (e.g. not all pointing to members of the same array) is unspecified, many implementations provide strict total ordering of pointers, e.g. if they are implemented as addresses within continuous virtual address space. Those implementations that do not (e.g. where not all bits of the pointer are part of a memory address and have to be ignored for comparison, or an additional calculation is required or otherwise pointer and integer is not a 1 to 1 relationship), provide a specialization of std::less for pointers that has that guarantee. This makes it possible to use all pointers of random origin as keys in standard associative containers such as std::set or std::map.
For the types that are both EqualityComparable and LessThanComparable, the C++ standard library makes a distinction between equality, which is the value of the expression a == b and equivalence, which is the value of the expression !(a < b) && !(b < a).
Comparison between pointers and null pointer constants was removed in C++14
void f(char * p) { if (p > 0) { ... } // OK in C++98..C++11, does not compile in C++14 if (p > nullptr) { ... } // OK in C++11, does not compile in C++14 }
Three-way comparisonThe three-way comparison operator expressions have the form
The expression returns an object such that
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 if one operand has unscoped enumeration type and the other has integral type, the usual arithmetic conversions are applied to the operands, and then
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 a pointer or pointer-to-member, array-to-pointer conversions, derived-to-base pointer conversions, function pointer conversions, and qualification conversions are applied as necessary to convert both operands to the same pointer type. If the resulting pointer type is a function pointer, a pointer to member, or std::nullptr_t, p <=> q returns a prvalue of type std::strong_equality:
If the resulting pointer type is an object pointer type, p <=> q returns a prvalue of type strong_ordering:
In overload resolution against user-defined operators, for pointer or enumeration type
Where R is the ordering category type defined above. For every T that is a pointer-to-member type or the type std::nullptr_t, the following function signature participates in overload resolution:
NotesThree-way comparison can be automatically generated for class types, see default comparisons If both of the operands are arrays, three-way comparison is ill-formed except when comparing class members of array type. unsigned int i = 1; auto r = -1 < i; // existing pitfall: returns false auto r2 = -1 <=> i; // Error: narrowing conversion required
|
(since C++20) |
Standard library
Comparison operators are overloaded for many classes in the standard library.
checks whether the objects refer to the same type (public member function of std::type_info ) | |
compares two error_code s (function) | |
compares error_conditions and error_codes (function) | |
lexicographically compares the values in the pair (function template) | |
lexicographically compares the values in the tuple (function template) | |
compares the contents (public member function of std::bitset ) | |
compares two allocator instances (public member function of std::allocator ) | |
compares to another unique_ptr or with nullptr (function template) | |
compares with another shared_ptr or with nullptr (function template) | |
compares a std::function with nullptr (function template) | |
compares two durations (function template) | |
compares two time points (function template) | |
compares two scoped_allocator_adaptor instances (public member function of std::scoped_allocator_adaptor ) | |
compares the underlying std::type_info objects (public member function of std::type_index ) | |
lexicographically compares two strings (function template) | |
equality comparison between locale objects (public member function of std::locale ) | |
lexicographically compares the values in the array (function template) | |
lexicographically compares the values in the deque (function template) | |
lexicographically compares the values in the forward_list (function template) | |
lexicographically compares the values in the list (function template) | |
lexicographically compares the values in the vector (function template) | |
lexicographically compares the values in the map (function template) | |
lexicographically compares the values in the multimap (function template) | |
lexicographically compares the values in the set (function template) | |
lexicographically compares the values in the multiset (function template) | |
compares the values in the unordered_map (function template) | |
compares the values in the unordered_multimap (function template) | |
compares the values in the unordered_set (function template) | |
compares the values in the unordered_multiset (function template) | |
lexicographically compares the values in the queue (function template) | |
lexicographically compares the values in the stack (function template) | |
compares the underlying iterators (function template) | |
compares the underlying iterators (function template) | |
compares two istream_iterator s (function template) | |
compares two istreambuf_iterator s (function template) | |
compares two complex numbers or a complex and a scalar (function template) | |
compares two valarrays or a valarray with a value (function template) | |
compares the internal states of two pseudo-random number engines (function template) | |
compares two distribution objects (function) | |
compares two sub_match objects (function template) | |
lexicographically compares the values in the two match result (function template) | |
compares two regex_iterator s (public member function of std::regex_iterator ) | |
compares two regex_token_iterator s (public member function of std::regex_token_iterator ) | |
compares two thread::id objects (function) |
The namespace rel_ops provides generic operators !=, >, <=, and >=
Defined in header
<utility> | |
Defined in namespace
std::rel_ops | |
(deprecated in C++20) |
automatically generates comparison operators based on user-defined operator== and operator< (function template) |
See also
Common operators | ||||||
---|---|---|---|---|---|---|
assignment | increment decrement |
arithmetic | logical | comparison | member access |
other |
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
Special operators | ||||||
static_cast converts one type to another related type |