Чтобы вы лучше осознали принципиальный характер различий между равенством и эквивалентностью, рассмотрим пример — контейнер set
struct CiStringCompare:// Класс сравнения строк
public// без учета регистра символов;
binary_function
// приведено в совете 40
bool operator() (const string& lhs,
const string& rhs) const
{
return ciStringCompare(lhs,rhs); // Реализация ciStringCompare
// приведена в совете 35
}
};
При наличии CiStringCompare контейнер set
set
Теперь при вставке строк «Persephone» и «persephone» в множество будет включена только первая строка, поскольку вторая считается эквивалентной:
ciss.insert("Persephone"); // В множество включается новый элемент
ciss.insert("persephone"); // Эквивалентный элемент не включается
Если теперь провести поиск строки «persephone» функцией set::find, результат будет успешным:
if(ciss.find("persephone")!=ciss.end())... // Элемент найден
Но если воспользоваться внешним алгоритмом find, поиск завершается неудачей:
if(find(ciss.begin(),ciss.end(),
"persephone")!=ciss.end())... // Элемент отсутствует
Дело в том, что строка «persephone»
Возникает вопрос — почему же в работе стандартных ассоциативных контейнеров используется понятие эквивалентности, а не равенства? Ведь большинству программистов равенство кажется интуитивно более понятным, чем эквивалентность (в противном случае данный совет был бы лишним). На первый взгляд ответ кажется простым, но чем дольше размышляешь над этим вопросом, тем менее очевидным он становится.
Стандартные ассоциативные контейнеры сортируются, поэтому каждый контейнер должен иметь функцию сравнения (по умолчанию less), определяющую порядок сортировки. Эквивалентность определяется в контексте функции сравнения, поэтому клиентам стандартных ассоциативных контейнеров остается лишь задать единственную функцию сравнения. Если бы ассоциативные контейнеры при сравнении объектов использовали критерий равенства, то каждому ассоциативному контейнеру, помимо используемой при сортировке функции сравнения, пришлось бы определять вторую функцию для проверки равенства. Вероятно, по умолчанию функция сравнения вызывала бы equal_to, но интересно заметить, что функция equal_to в STL не используется в качестве стандартной функции сравнения. Когда в STL возникает необходимость проверки равенства, по умолчанию просто вызывается оператор =. В частности, именно так поступает внешний алгоритм find.
Допустим, у нас имеется контейнер set2CF, построенный по образцу set — «set с двумя функциями сравнения». Первая функция сравнения определяет порядок сортировки элементов множества, а вторая используется для проверки равенства. А теперь рассмотрим следующее объявление:
set2CF
Контейнер s производит внутреннюю сортировку строк без учета регистра, но с использованием интуитивного критерия равенства: две строки считаются равными при совпадении их содержимого. Предположим, в s вставляются два варианта написания строки «Persephone»:
s.insert("Persephone");
s.insert("persephone");