Операторы сравнения
Сравнивает аргументы.
| Имя оператора | Синтаксис | Перегружаемый | Примеры прототипов (для class T) | |
|---|---|---|---|---|
| Внутри определения класса | За пределами определения класса | |||
| равен |
a == b | Да |
bool T::operator==(const U& b) const; |
bool operator==(const T& a, const U& b); |
| не равно |
a != b | Да |
bool T::operator!=(const U& b) const; |
bool operator!=(const T& a, const U& b); |
| меньше |
a < b | Да |
bool T::operator<(const U& b) const; |
bool operator<(const T& a, const U& b); |
| больше |
a > b | Да |
bool T::operator>(const U& b) const; |
bool operator>(const T& a, const U& b); |
| меньше или равно |
a <= b | Да |
bool T::operator<=(const U& b) const; |
bool operator<=(const T& a, const U& b); |
| больше или равно |
a >= b | Да |
bool T::operator>=(const U& b) const; |
bool operator>=(const T& a, const U& b); |
| сравнение с тремя знаками (C++20) |
a <=> b | Да |
R T::operator<=>(const U& b) const;[1] |
R operator<=>(const T& a, const U& b);[1] |
Примечания
|
||||
Двухстороннее сравнение
Выражения операторов двустороннего сравнения имеют вид
Операторы отношения
lhs < rhs | (1) | |
lhs > rhs | (2) | |
lhs <= rhs | (3) | |
lhs >= rhs | (4) |
Операторы равенства
lhs == rhs | (5) | |
lhs != rhs | (6) |
true , если lhs меньше rhs, false в противном случае.true , если lhs больше rhs, false в противном случае.true , если lhs меньше или равно rhs, false в противном случае.true , если lhs больше или равно rhs, false в противном случае.true , если lhs равно rhs, false в противном случае.true , если lhs не равно rhs, false в противном случае.Встроенные операторы двустороннего сравнения
Для встроенных операторов применяются преобразования lvalue-to-rvalue, преобразования массива в указатель и преобразования функции в указатель к lhs и rhs. Сравнение устарело, если у lhs и rhs тип массива до применения этих преобразований.(с C++20)
Для встроенных операторов результатом является prvalue типа bool.
Встроенное арифметическое сравнение
Если преобразованные операнды имеют арифметический или перечислительный тип (глобальный или локальный), для обоих операндов выполняется обычное арифметическое преобразование. Значения сравниваются после преобразований:
#include <iostream>
int main()
{
static_assert(sizeof(unsigned char) < sizeof(int),
"Can't compare signed and smaller unsigned properly");
int a = -1;
int b = 1;
unsigned int c = 1;
unsigned char d = 1;
std::cout
<< std::boolalpha
<< "Comparing two signed values:\n"
<< " -1 == 1 ? " << (a == b) << '\n'
<< " -1 < 1 ? " << (a < b) << '\n'
<< " -1 > 1 ? " << (a > b) << '\n'
<< "Comparing signed and unsigned:\n"
<< " -1 == 1 ? " << (a == c) << '\n' // may issue different-signedness warning
<< " -1 < 1 ? " << (a < c) << '\n' // may issue different-signedness warning
<< " -1 > 1 ? " << (a > c) << '\n' // may issue different-signedness warning
<< "Comparing signed and smaller unsigned:\n"
<< " -1 == 1 ? " << (a == d) << '\n'
<< " -1 < 1 ? " << (a < d) << '\n'
<< " -1 > 1 ? " << (a > d) << '\n';
}Вывод:
Comparing two signed values: -1 == 1 ? false -1 < 1 ? true -1 > 1 ? false Comparing signed and unsigned: -1 == 1 ? false -1 < 1 ? false -1 > 1 ? true Comparing signed and smaller unsigned: -1 == 1 ? false -1 < 1 ? true -1 > 1 ? false
Встроенное сравнение на равенство указателей
Преобразованные операнды операторов равенства == и != также могут иметь тип std::nullptr_t,(с C++11) указатель или указатель на член.
Встроенное сравнение указателей на равенство имеет три возможных результата: равенство, неравенство и неопределенность. Значения, возвращаемые операторами равенства для встроенного сравнения указателей, перечислены ниже:
Результат сравнения p и q | Возвращаемое значение | |
|---|---|---|
p == q |
p != q |
|
| равенство |
true |
false |
| неравенство |
false |
true |
| неопределенность | неопределенное значение типа bool | |
Если хотя бы один из преобразованных lhs и rhs является указателем, применяются преобразования указателей, преобразования указателей на функции,(с C++17) и преобразования квалификаций для обоих преобразованных операндов, чтобы привести их к их составному типу указателя. Два указателя составного типа указателя сравниваются следующим образом:
- Если один указатель представляет адрес полного объекта, а другой указатель
-
- представляет адрес после конца другого полного объекта, не являющегося массивом, или
- представляет адрес, следующий за последним элементом другого полного объекта-массива,
- результат сравнения не определен.
- В противном случае, если оба указателя равны нулю, оба указывают на одну и ту же функцию или оба представляют один и тот же адрес (т. е., они указывают на или находятся после конца одного и того же объекта), они равны.
- В противном случае указатели не равны.
Если хотя бы один из преобразованных lhs и rhs является указателем на член, применяются преобразования указателей на члены, преобразования указателей на функции,(с C++17) и преобразования квалификаций для обоих преобразованных операндов, чтобы привести их к их составному типу указателя. Два указателя на члены составного типа указателя сравниваются следующим образом:
- Если два указателя на члены имеют значение нулевого указателя на член, они равны.
- Если только один из двух указателей на члены имеет значение нулевого указателя на член, они не равны.
- Если один из них является указателем на виртуальную функцию члена, результат не определен.
- Если один относится к члену класса
C1, а другой - к члену другого классаC2, где ни один не является базовым классом другого, результат не определен. - Если оба относятся (возможно, к разным) членам одного и того же объединения, они равны.
- В противном случае два указателя на члены сравниваются как равные, если они ссылались бы на один и тот же член одного и того же наиболее производного объекта или на один и тот же подобъект, если бы была выполнена косвенная ссылка с гипотетическим объектом соответствующего типа класса, в противном случае они не равны.
struct P {};
struct Q : P { int x; };
struct R : P { int x; };
int P::*bx = (int(P::*)) &Q::x;
int P::*cx = (int(P::*)) &R::x;
bool b1 = (bx == cx); // unspecified
struct B
{
int f();
};
struct L : B {};
struct R : B {};
struct D : L, R {};
int (B::*pb)() = &B::f;
int (L::*pl)() = pb;
int (R::*pr)() = pb;
int (D::*pdl)() = pl;
int (D::*pdr)() = pr;
bool x = (pdl == pdr); // false
bool y = (pb == pl); // true| Два операнда типа | (с C++11) |
Встроенное сравнение указателей по отношению
Преобразованные операнды реляционных операторов >, <, >= и <= также могут иметь тип указателя.
Встроенное сравнение указателей по отношению при неравных указателях p и q имеет три возможных результата: p больше, q больше и неопределённый. Значения, возвращаемые реляционными операторами для встроенного сравнения указателей по отношению, перечислены ниже:
Результат сравнения p и q | Возвращаемое значение | |||
|---|---|---|---|---|
p > q | p < q | p >= q | p <= q |
|
| равны |
false |
false |
true |
true |
p больше |
true |
false |
true |
false |
q больше |
false |
true |
false |
true |
| неопределённый | неопределённое значение типа bool | |||
Если преобразованные lhs и rhs являются указателями, преобразования указателей, преобразования указателей на функции(с C++17) и преобразования квалификаций выполняются для обоих преобразованных операндов, чтобы привести их к их составному типу указателя. Два указателя составного типа сравниваются следующим образом:
- Если указатели равны или результат сравнения на равенство неопределённый, результат реляционного сравнения попадает в ту же категорию.
- В противном случае (указатели не равны), если какой-либо из указателей не является указателем на объект, результат неопределён.
- В противном случае (оба указателя указывают на объекты), результат определяется в терминах частичного порядка, согласованного со следующими правилами:
- Даны два разных элемента
highиlowмассива, таких чтоhighимеет больший индекс, чемlow, если один указатель указывает наhigh(или на подобъектhigh) а другой указывает наlow(или на подобъектlow), то первый сравнивается больше, чем второй. - Если один указатель указывает на элемент
elem(или на подобъектelem) массива, а другой указывает за пределы того же массива, указатель за пределами массива сравнивается больше, чем другой указатель. - Если один указатель указывает на полный объект, подобъект базового класса или подобъект члена
obj(или на подобъектobj) а другой указывает за пределыobj, указатель за пределами сравнивается больше, чем другой указатель.
- Если указатели указывают на разные не нулевые(с C++20) нестатические члены данных с тем же доступом(до C++23) одного объекта типа не объединения, или на подобъекты таких членов, рекурсивно, указатель на объявленный позже член сравнивается больше, чем другой указатель.
- В противном случае, результат неопределён.
Полный порядок указателей
В каждой программе существует определяемое реализацией строгое полное упорядочение над указателями. Строгое полное упорядочение согласовано с частичным порядком, описанным выше: неопределённые результаты становятся определяемыми реализацией, а другие результаты остаются такими же.
Сравнение указателей со строгим полным порядком применяется в следующих случаях:
- Вызов оператора() специализаций типа указателя
std::less,std::greater,std::less_equalиstd::greater_equal.
| (с C++14) |
| (с C++20) |
Перегрузки
В разрешении перегрузки против пользовательских операторов, для каждой пары повышенных арифметических типов L и R, включая типы перечислений, в разрешении перегрузки участвуют следующие подписи функций:
bool operator<(L, R); | ||
bool operator>(L, R); | ||
bool operator<=(L, R); | ||
bool operator>=(L, R); | ||
bool operator==(L, R); | ||
bool operator!=(L, R); |
Для каждого типа P, который является либо указателем на объект, либо указателем на функцию, в разрешении перегрузки участвуют следующие подписи функций:
bool operator<(P, P); | ||
bool operator>(P, P); | ||
bool operator<=(P, P); | ||
bool operator>=(P, P); | ||
bool operator==(P, P); | ||
bool operator!=(P, P); |
Для каждого типа MP, который является указателем на член объекта или указателем на член функции или std::nullptr_t(с C++11), в разрешении перегрузки участвуют следующие подписи функций:
bool operator==(MP, MP); | ||
bool operator!=(MP, MP); |
#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:\n"
<< "p1 == p2? " << (p1 == p2) << '\n'
<< "p1 < p2? " << (p1 < p2) << '\n';
Foo f;
int* p3 = &f.n1;
int* p4 = &f.n2;
std::cout << "Pointers to members of a class:\n"
<< "p3 == p4? " << (p3 == p4) << '\n'
<< "p3 < p4? " << (p3 < p4) << '\n';
Union u;
int* p5 = &u.n;
double* p6 = &u.d;
std::cout << "Pointers to members of a union:\n"
<< "p5 == (void*)p6? " << (p5 == (void*)p6) << '\n'
<< "p5 < (void*)p6? " << (p5 < (void*)p6) << '\n';
}Вывод:
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 < (void*)p6? false
Трехстороннее сравнениеВыражения оператора трехстороннего сравнения имеют вид
Выражение возвращает объект, такой что
Если один из операндов имеет тип bool, а другой — нет, программа является некорректной. Если оба операнда имеют арифметические типы или один операнд имеет тип неименованного перечисления, а другой — целочисленный тип, к операндам применяются обычные арифметические преобразования, а затем
Если оба операнда имеют одинаковый тип перечисления Если хотя бы один из операндов является указателем на объект или указателем на член, применяются преобразования массива в указатель, преобразования указателей и преобразования квалификаций к обоим операндам для приведения их к их составному типу указателя. Для преобразованных указанных операндов
В противном случае, программа является некорректной. ПерегрузкиПри разрешении перегрузки по отношению к пользовательским операторам для указателя или перечисления
Где #include <compare>
#include <iostream>
int main()
{
double foo = -0.0;
double bar = 0.0;
auto res = foo <=> bar;
if (res < 0)
std::cout << "-0 is less than 0";
else if (res > 0)
std::cout << "-0 is greater than 0";
else if (res == 0)
std::cout << "-0 and 0 are equal";
else
std::cout << "-0 and 0 are unordered";
}Вывод: -0 and 0 are equal | (с C++20) |
Примечания
Поскольку операторы сравнения группируются слева направо, выражение a < b < c анализируется (a < b) < c, а не a < (b < c) или (a < b) && (b < c).
#include <iostream>
int main()
{
int a = 3, b = 2, c = 1;
std::cout << std::boolalpha
<< (a < b < c) << '\n' // true; maybe warning
<< ((a < b) < c) << '\n' // true
<< (a < (b < c)) << '\n' // false
<< ((a < b) && (b < c)) << '\n'; // false
}Общее требование для пользовательского оператора < — строгое слабое упорядочение. В частности, это требуется стандартными алгоритмами и контейнерами, работающими с типами Compare: std::sort, std::max_element, std::map, и т. д.
Результат сравнения указателей на разные нестатические члены одного класса предполагает, что нестатические члены в каждом из трех режимов доступа к членам(до C++23) располагаются в памяти в порядке объявления.
Хотя результаты сравнения указателей произвольного происхождения (например, не все указывающие на члены одного массива) не определены, многие реализации обеспечивают строгое полное упорядочение указателей, например, если они реализованы как адреса в непрерывном виртуальном адресном пространстве. Реализации, которые этого не делают (например, где не все биты указателя являются частью адреса памяти и должны быть проигнорированы при сравнении, или требуется дополнительное вычисление, или иначе указатель и целое число не имеют взаимно однозначного соответствия), обеспечивают специализацию std::less для указателей, имеющих это гарантию. Это позволяет использовать все указатели произвольного происхождения в качестве ключей в стандартных ассоциативных контейнерах, таких как std::set или std::map.
Для типов, которые являются одновременно EqualityComparable и LessThanComparable, стандартная библиотека C++ различает равенство, которое является значением выражения a == b, и эквивалентность, которое является значением выражения !(a < b) && !(b < a).
Сравнение указателей и констант нулевого указателя было удалено в результате решения CWG issue 583, включенного в N3624:
void f(char* p)
{
if (p > 0) { /*...*/ } // Error with N3624, compiled before N3624
if (p > nullptr) { /*...*/ } // Error with N3624, compiled before N3624
}
int main() {}Трехстороннее сравнение может быть автоматически сгенерировано для типов классов, см. стандартные сравнения.
Если оба операнда являются массивами, трехстороннее сравнение некорректно.
unsigned int i = 1; auto r = -1 < i; // existing pitfall: returns ‘false’ auto r2 = -1 <=> i; // Error: narrowing conversion required
| Макрос проверки функций | Значение | Std | Функция |
|---|---|---|---|
__cpp_impl_three_way_comparison | 201907L | (C++20) | Трехстороннее сравнение (поддержка компилятора) |
__cpp_lib_three_way_comparison | 201907L | (C++20) | Трехстороннее сравнение (поддержка библиотеки); добавление трехстороннего сравнения в библиотеку |
Стандартная библиотека
Операторы сравнения перегружены для многих классов в стандартной библиотеке.
|
(удалено в C++20) | проверяет, ссылаются ли объекты на один и тот же тип (публичный член-функция std::type_info) |
|
(удалено в C++20)(удалено в C++20)(C++20) | сравнивает два объекта error_code (функция) |
|
(удалено в C++20)(удалено в C++20)(C++20) | сравнивает объекты error_condition и error_code (функция) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | лексикографически сравнивает значения в паре (шаблон функции) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | лексикографически сравнивает значения в кортеже (шаблон функции) |
|
(удалено в C++20) | сравнивает содержимое (публичный член-функция std::bitset<N>) |
|
(удалено в C++20) | сравнивает два экземпляра аллокатора (публичный член-функция std::allocator<T>) |
|
(удалено в C++20)(C++20) | сравнивает с другим объектом unique_ptr или с nullptr (шаблон функции) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | сравнивает с другим shared_ptr или с nullptr (шаблон функции) |
|
(удалено в C++20) | сравнивает std::function с nullptr (шаблон функции) |
|
(C++11)(C++11)(удалено в C++20)(C++11)(C++11)(C++11)(C++11)(C++20) | сравнивает две продолжительности (шаблон функции) |
|
(C++11)(C++11)(удалено в C++20)(C++11)(C++11)(C++11)(C++11)(C++20) | сравнивает две точки времени (шаблон функции) |
|
(удалено в C++20) | сравнивает два экземпляра scoped_allocator_adaptor (шаблон функции) |
|
(удалено в C++20)(C++20) | сравнивает лежащие в основе объекты std::type_info (публичный член-функция std::type_index) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | лексикографически сравнивает две строки (шаблон функции) |
|
(удалено в C++20) | сравнение на равенство объектов locale (публичный член-функция std::locale) |
|
(C++11)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++20) | лексикографически сравнивает значения двух arrays (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух deques (function template) |
|
(C++11)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++11)(removed in C++20)(C++20) | лексикографически сравнивает значения двух forward_lists (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух lists (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух vectors (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух maps (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух multimaps (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух sets (function template) |
|
(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(removed in C++20)(C++20) | лексикографически сравнивает значения двух multisets (function template) |
|
(C++11)(C++11)(removed in C++20) | сравнивает значения в unordered_map (function template) |
|
(C++11)(C++11)(removed in C++20) | сравнивает значения в unordered_multimap (function template) |
|
(C++11)(C++11)(removed in C++20) | сравнивает значения в unordered_set (function template) |
|
(C++11)(C++11)(removed in C++20) | сравнивает значения в unordered_multiset (function template) |
|
(C++20) | лексикографически сравнивает значения двух queues (шаблон функции) |
|
(C++20) | лексикографически сравнивает значения двух stacks (шаблон функции) |
|
(C++20) | сравнивает базовые итераторы (шаблон функции) |
|
(C++11)(C++11)(удалено в C++20)(C++11)(C++11)(C++11)(C++11)(C++20) | сравнивает базовые итераторы (шаблон функции) |
|
(удалено в C++20) | сравнивает два istream_iterator (шаблон функции) |
|
(удалено в C++20) | сравнивает два istreambuf_iterator (шаблон функции) |
|
(удалено в C++20) | сравнивает два комплексных числа или комплексное число и скаляр (шаблон функции) |
| сравнивает два valarray или valarray со значением (шаблон функции) |
|
|
(C++11)(C++11)(удалено в C++20) | сравнивает внутренние состояния двух псевдослучайных генераторов чисел (функция) |
|
(C++11)(C++11)(удалено в C++20) | сравнивает два объекта распределения (функция) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | сравнивает sub_match с другим sub_match, строкой или символом (шаблон функции) |
|
(удалено в C++20) | лексикографически сравнивает значения в двух результатах совпадения (шаблон функции) |
|
(удалено в C++20) | сравнивает два regex_iterator (публичный член-функция std::regex_iterator<BidirIt,CharT,Traits>) |
|
(удалено в C++20) | сравнивает два regex_token_iterator (публичный член-функция std::regex_token_iterator<BidirIt,CharT,Traits>) |
|
(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(удалено в C++20)(C++20) | сравнивает два объекта thread::id (функция) |
Пространство имен std::rel_ops предоставляет универсальные операторы !=, >, <=, и >=:
Определено в заголовке <utility> |
|
|---|---|
Определено в пространстве имен std::rel_ops |
|
|
(устарело в C++20) | автоматически генерирует операторы сравнения, основанные на пользовательских operator== и operator< (шаблон функции) |
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение, опубликованное | Правильное поведение |
|---|---|---|---|
|
CWG 583 (N3624) | C++98 | все шесть операторов сравнения можно было использовать для сравнения указателя с константой нулевого указателя | разрешены только операторы равенства |
| CWG 661 | C++98 | фактическая семантика арифметических сравнений (например, то, что 1 < 2 приводит к true или false) не была определена | добавлено описание |
| CWG 879 | C++98 | указатели на типы функций и указатели на void не имели встроенных сравнений | добавлено описание сравнения для этих указателей |
| CWG 1596 | C++98 | объекты, не являющиеся массивами, считались принадлежащими массивам с одним элементом только для целей арифметики указателей | правило также применяется к сравнениям |
| CWG 1598 | C++98 | два указателя на члены классов, которые отличаются и ни один из них не является базовым классом другого, не сравнивались как равные даже если смещения указываемых членов могут быть одинаковыми | результат неопределён в этом случае |
| CWG 1858 | C++98 | не было ясно, сравниваются ли два указателя на члены, которые ссылаются на разные члены одного объединения, как равные, как если бы они ссылались на один и тот же член | они сравниваются как равные в этом случае |
| CWG 2419 | C++98 | указатель на объект, не являющийся массивом, рассматривался только как указатель на первый элемент массива с размером 1 в сравнении указателей, если указатель получен путем & | применяется ко всем указателям на объекты, не являющиеся массивами |
| CWG 2526 | C++98 | определение реляционного сравнения (>, >=, < и <=) указателей на void и указателей на функции были удалены посредством N3624 | восстановлено |
См. также
- Порядок приоритета операторов
- Перегрузка операторов
- Compare (названные требования)
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание |
инкремент декремент | арифметические | логические | сравнения |
доступ к членам | прочие |
|
|
|
|
|
|
| вызов функции |
a(...) |
||||||
| запятая | ||||||
a, b |
||||||
| условный | ||||||
a ? b : c |
||||||
| Специальные операторы | ||||||
|
|
||||||
| Документация C по Операторам сравнения |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/operator_comparison