Совет 19. Помните о различиях между равенством и эквивалентностью
Алгоритм find
и функция set::insert являются типичными представителями семейства функций, проверяющих совпадение двух величин, однако делают это они по-разному. Для find совпадением считаетсяФормальное определение равенства основано на использовании оператора =. Если результат выражения х=у равен true,
значит, х и у имеют одинаковые значения, а если false — разные. В целом определение весьма прямолинейное, хотя следует помнить о том, что из равенства значений не следует равенство всех полей данных. Предположим, класс Widget хранит внутренние данные о времени последнего обращения:class Widget {
public:
private:
TimeStamp lastAccessed;
};
Для класса Widget
можно определить оператор ==, игнорирующий значение этого поля:bool operator=(const Widgets Ihs, const Widgets rhs) {
// Поле lastAccessed игнорируется
}
В этом случае два объекта Widget
будут считаться равными даже в том случае, если их поляlastAccessed
содержат разные значения.Эквивалентность основана на относительном порядке значений объектов в отсортированном интервале. Проще всего рассматривать ее в контексте порядка сортировки, являющегося частью любого стандартного ассоциативного контейнера (то есть set, multiset, map
и multimap). Два объекта х и у считаются эквивалентными по отношению к порядку сортировки, используемому ассоциативным контейнером с, если ни один из них не предшествует другому в порядке сортировки с. На первый взгляд такая формулировка кажется запутанной, но на практике все просто. Возьмем контейнер set!(w1
&& // и
!(w2
Все вполне логично: два значения эквивалентны (по отношению к некоторому критерию упорядочения), если ни одно из них не предшествует другому в соответствии с данным критерием.
В общем случае функцией сравнения для ассоциативного контейнера является не оператор < или даже less, а пользовательский предикат (см. совет 39). Каждый стандартный ассоциативный контейнер предоставляет свой предикат сортировки через функцию key_comp
!c.key_comp()(x.y) && !c.key_comp()(y,x) // х не предшествует у
// в порядке сортировки с,
// а у не предшествует х
Выражение !c.key_comp()(x,y)
c.key_comp()
возвращает функцию (или объект функции), как все затруднения исчезают. Перед нами простой вызов функции (или объекта функции), возвращаемой key_comp
, которой передаются аргументы х и у. Затем вычисляется логическое отрицание результата. Функция с.keycomp ()(х, у)
возвращает true
лишь в том случае, если х предшествует у в порядке сортировки, поэтому выражение !с.key_comp()(х, у)
истинно только в том случае, если х