Comparison operators

From cppreference.com
< cpp‎ | language

Compares the arguments.

Operator name Syntax Over​load​able Prototype examples (for class T)
Inside class definition Outside class definition
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);
Notes
  • All built-in operators return bool, and most user-defined overloads also return bool so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void).
  • T2 can be any type including T

Contents

[edit] Explanation

Returns the boolean result of comparison of the values of the arguments, which are not modified.

[edit] Arithmetic comparison 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);

If the operands has arithmetic or enumeration type (scoped or unscoped), usual arithmetic conversions are performed following the rules for arithmetic operators. The values are compared after conversions:

[edit] 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

[edit] Pointer comparison operators

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);

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) and qualification conversions are applied to both operands to obtain the composite pointer type, as follows

1) If both operands are null pointer constants, the composite pointer type is std::nullptr_t
2) If one operand a null pointer constant and the other is a pointer, the composite type is exactly the pointer type
3) 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)
3) If the types of the operands are P1, a pointer to cv-qualified T1, and P2, a pointer to cv-qualified T2, and if T1 is reference-related to T2, then the composite pointer type is the cv-combined type of P1 and P2. Otherwise, if T2 is reference-related to T1, then the composite pointer type is the cv-combined type of P2 and P1.
4) If the types of the operands are MP1, pointer to member of T1 of cv-qualified U1 and MP2, pointer to member of C2 of cv-qualified U2, and if T1 is reference-related to T2, then the composite pointer type is the cv-combined type of P2 and P1. Otherwise, if T2 is reference-related to T2, then the composite pointer type is the cv-combined type of P1 and P2.
5) if the types of the operands P1 and P2 are similar multi-level mixed pointer and pointer to member types, 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 similar to P1 whose cv-qualification is:

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)

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:

1) If two pointers point to different elements of the same array, or to subobjects within different elements of the same array, the pointer to the element with the higher subscript compares greater. In other wise, they results of comparing the pointers is the same as the result of comparing the indexes of the elements they point to.
2) If one pointer points to an element of an array, or to a subobject of the element of the array, and another pointer points one past the last element of the array, the latter pointer compares greater.
3) If, within an object of non-union class type, two pointers point to different non-static data members with the same member access, or to subobjects or array elements of such members, recursively, the pointer to the later declared member compares greater. In other words, class members in each of the three member access modes are positioned in memory in order of declaration.

The result of equality comparison of two pointers (after conversions) is defined as follows:

1) If the pointers are both null pointer values, they compare equal
2) If the pointers are pointers to function and point to the same function, then compare equal
3) If the pointers are pointers to object and represent the same address, they compare equal (this includes two pointers to non-static members of the same union, pointers to standard-layout struct and to its first member, pointers related by reinterpret_cast, etc)
4) All other pointers compare unequal

The result of comparing two pointers to members (after conversions) is defined as follows:

1) If both pointers to member are null member pointer values, they compare equal.
2) Otherwise, if only one of two pointers to member is the null member pointer value, they compare unequal.
3) Otherwise, if either is a pointer to a virtual member function, the result is unspecified.
4) Otherwise, two pointers to member compare equal if and only if they would refer to the same member of the same most derived object or the same subobject if they were dereferenced with a hypothetical object of the associated class type
5) Otherwise they compare unequal.

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.

[edit] 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

[edit] 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++98..C++11, does not compile in C++14
}

[edit] 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_codes
(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 an std::function with std::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_iterators
(function template)
compares two istreambuf_iterators
(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)
compares two distribution objects
(function)
compares two sub_match objects
(function)
lexicographically compares the values in the two match result
(function template)
compares two regex_iterators
(public member function of std::regex_iterator)
compares two regex_token_iterators
(public member function of std::regex_token_iterator)
compares two thread::id objects
(function)
automatically generates comparison operators based on user-defined operator== and operator<
(function template)

[edit] See also

Operator precedence

Common operators
assignment increment
decrement
arithmetic logical comparison member
access
other

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b

a[b]
*a
&a
a->b
a.b
a->*b
a.*b

a(...)
a, b
(type) a
? :

Special operators

static_cast converts one type to another compatible type
dynamic_cast converts virtual base class to derived class
const_cast converts type to compatible type with different cv qualifiers
reinterpret_cast converts type to incompatible type
new allocates memory
delete deallocates memory
sizeof queries the size of a type
sizeof... queries the size of a parameter pack (since C++11)
typeid queries the type information of a type
noexcept checks if an expression can throw an exception (since C++11)
alignof queries alignment requirements of a type (since C++11)