void f(list
{
list
if (p!=v.end()) { /* мы нашли x */ }
// ...
}
find()
, являются операциями над итераторами класса list
. Эти операторы имеют соответствующий смысл, так что логика их работы совпадает с логикой работы операторов из предыдущего примера (для класса vector
). В то же время они реализованы совершенно по-разному; иначе говоря, оператор ++
(в выражении ++first
) просто следует за указателем, установленным на следующий узел списка, а оператор *
(в выражении *first
) находит значение в узле Link
. Сравнение итераторов (в выражении first!=last
) сводится к сравнению указателей типа Link*
, а сравнение значений (в выражении *first!=val
) означает сравнение строк с помощью оператора !=
из класса string
.
Итак, алгоритм find()
чрезвычайно гибкий: если мы будем соблюдать простые правила работы с итераторами, то сможем использовать алгоритм find()
для поиска элементов в любой последовательности любого контейнера. Например, с помощью алгоритма find()
мы можем искать символ в объекте класса Document, определенного в разделе 20.6.
void f(Document& v,char x) // работает с объектами класса Document
{
Text_iterator p = find(v.begin(),v.end(),x);
if (p!=v.end()) { /* мы нашли x */ }
// ...
}
Эта гибкость является отличительной чертой алгоритмов из библиотеки STL и делает их более полезными, чем многие люди могут себе представить.
21.3. Универсальный алгоритм поиска: find_if()
Нам редко приходится искать какое-то конкретное значение. Чаще нас интересует значение, удовлетворяющее определенным критериям. Мы смогли бы выполнять намного более полезную операцию find
, если бы могли определять свои собственные критерии поиска. Например, мы могли бы найти число, превышающее 42
. Мы могли бы также сравнивать строки, не учитывая регистр (верхний или нижний).
Кроме того, мы могли найти первое нечетное число. А может, мы захотели бы найти запись с адресом "17 Cherry Tree Lane
".
Стандартный алгоритм поиска в соответствии с критерием, заданным пользователем, называется find_if()
.
template
In find_if(In first,In last,Pred pred)
{
while (first!=last && !pred(*first)) ++first;
return first;
}
Очевидно (если сравнить исходные коды), что он похож на алгоритм find()
, за исключением того, что в нем используется условие !pred(*first)
, а не *first!=val
; иначе говоря, алгоритм останавливает поиск, как только предикат pred()
окажется истинным, а не когда будет обнаружен элемент с заданным значением.
true
или false
. Очевидно, что алгоритм find_if()
требует предиката, принимающего один аргумент, чтобы выражение pred(*first)
было корректным. Мы можем без труда написать предикат, проверяющий какое-то свойство значения, например “содержит ли строка букву
bool odd(int x) { return x%2; } // % — деление по модулю
void f(vector
{
vector
if (p!=v.end()) { /* мы нашли нечетное число */ }
// ...
}
При данном вызове алгоритм find_if()
применит функцию odd()
к каждому элементу, пока не найдет первое нечетное число. Аналогично, мы можем найти первый элемент списка, значение которого превышает 42.
bool larger_than_42(double x) { return x>42; }
void f(list
{
list
larger_than_42);
if (p!=v.end()) { /* мы нашли значение, превышающее 42 */ }
// ...
}
Однако последний пример не вполне удовлетворительный. А что, если мы после этого захотим найти элемент, который больше 41? Нам придется написать новую функцию. Хотите найти элемент, который больше 19? Пишите еще одну функцию. Должен быть более удобный способ!