Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

}

Очевидно (если сравнить исходные коды), что он похож на алгоритм

find
, за исключением того, что в нем используется условие
!pred(*first)
, а не
*first!=val
; иначе говоря, алгоритм останавливает поиск, как только предикат
pred
окажется истинным, а не когда будет обнаружен элемент с заданным значением.

Предикат (predicate) — это функция, возвращающая значение
true
или
false
. Очевидно, что алгоритм
find_if
требует предиката, принимающего один аргумент, чтобы выражение
pred(*first)
было корректным. Мы можем без труда написать предикат, проверяющий какое-то свойство значения, например “содержит ли строка букву x”, “превышает ли число значение 42” или “является ли число нечетным?” Например, мы можем найти первое нечетное число в целочисленном векторе.

bool odd(int x) { return x%2; } // % — деление по модулю

void f(vector<int>& v)

{

vector<int>::iterator p = find_if(v.begin, v.end, odd);

if (p!=v.end) { /* мы нашли нечетное число */ }

// ...

}

При данном вызове алгоритм

find_if
применит функцию
odd
к каждому элементу, пока не найдет первое нечетное число. Аналогично, мы можем найти первый элемент списка, значение которого превышает 42.

bool larger_than_42(double x) { return x>42; }

void f(list<double>& v)

{

list<double>::iterator p = find_if(v.begin, v.end,

larger_than_42);

if (p!=v.end) { /* мы нашли значение, превышающее 42 */ }

// ...

}

Однако последний пример не вполне удовлетворительный. А что, если мы после этого захотим найти элемент, который больше 41? Нам придется написать новую функцию. Хотите найти элемент, который больше 19? Пишите еще одну функцию. Должен быть более удобный способ!

Если мы хотим сравнивать элемент с произвольным значением

v
, то должны как-то сделать это значение неявным аргументом предиката алгоритма
find_if
. Мы могли бы попробовать (выбрав в качестве удобного имени идентификатор
v_val
).

double v_val; // значение, с которым предикат larger_than_v

// сравнивает свой аргумент

bool larger_than_v(double x) { return x>v_val; }

void f(list<double>& v,int x)

{

v_val = 31; // устанавливаем переменную v_val равной 31,

// для следующего вызова предиката larger_than_v

list<double>::iterator p = find_if(v.begin,v.end,

larger_than_v);

if (p!=v.end) { /* мы нашли значение, превышающее 31 */ }

v_val = x; // устанавливаем переменную v_val равной x

// для следующего вызова предиката larger_than_v

list<double>::iterator q = find_if(v.begin, v.end,

larger_than_v);

if (q!=v.end) { /* мы нашли значение, превышающее x*/ }

// ...

}

Какая гадость! Мы убеждены, что люди, написавшие такую программу, в конце концов получат по заслугам, но мы заранее сочувствуем пользователям и любому человеку, который столкнется с этим кодом. Повторим: должен быть более удобный способ!

ПОПРОБУЙТЕ

Почему такое использование переменной

v
вызывает у нас такое отвращение? Назовите по крайней мере три способа, которые приведут к непонятным ошибкам. Назовите три приложения, в которых такие программы особенно недопустимы.

21.4. Объекты-функции

Итак, мы хотим передавать предикат алгоритму

find_if
и чтобы этот предикат сравнивал элементы со значением, которое мы зададим как его аргумент. В частности, мы хотим написать примерно такой код:

void f(list<double>& v, int x)

{

list<double>::iterator p = find_if(v.begin, v.end,

Larger_than(31));

if (p!=v.end) { /* мы нашли число, превышающее 31 */ }

list<double>::iterator q = find_if(v.begin, v.end,

Larger_than(x));

if (q!=v.end) { /* мы нашли число, превышающее x */ }

// ...

  • Читать дальше
  • 1
  • ...
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: