Читаем Программирование полностью

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

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

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

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

void f(list& v,int x)

{

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

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

  list::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::iterator q = find_if(v.begin(), v.end(),

                                     larger_than_v);

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

    // ...

}

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

ПОПРОБУЙТЕ

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

<p id="AutBody_Root394"><strong>21.4. Объекты-функции</strong></p>

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

void f(list& v, int x)

{

  list::iterator p = find_if(v.begin(), v.end(),

  Larger_than(31));

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

    list::iterator q = find_if(v.begin(), v.end(),

  Larger_than(x));

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

    // ...

}

Очевидно, что функция Larger_than должна удовлетворять двум условиям.

• Ее можно вызывать как предикат, например pred(*first).

• Она может хранить значение, например 31 или x, передаваемое при вызове.

  Для того чтобы выполнить эти условия, нам нужен объект-функция, т.е. объект, который ведет себя как функция. Нам нужен объект, поскольку именно объекты могут хранить данные, например значение для сравнения. Рассмотрим пример.

class Larger_than {

  int v;

public:

  Larger_than(int vv) : v(vv) { } // хранит аргумент

  bool operator()(int x) const { return x>v; } // сравнение

};

Следует отметить, что это определение представляет собой именно то, что мы требовали от предиката. Теперь осталось понять, как это работает. Написав выражение Larger_than(31), мы (очевидно) создаем объект класса Larger_than, хранящий число 31 в члене v. Рассмотрим пример.

find_if(v.begin(),v.end(),Larger_than(31))

Здесь мы передаем объект Larger_than(31) алгоритму find_if() как параметр с именем pred. Для каждого элемента v алгоритм find_if() осуществляет вызов

pred(*first)

Это активизирует оператор вызова функции, т.е. функцию-член operator(), для объекта-функции с аргументом *first. В результате происходит сравнение значения элемента, т.е. *first, с числом 31.

Мы видим, что вызов функции можно рассматривать как результат работы оператора (), аналогично любому другому оператору. Оператор () называют также оператором вызова функции (function call operator) или прикладным оператором (application operator). Итак, оператор () в выражении pred(*first) эквивалентен оператору Larger_than::operator(), точно так же, как оператор [] в выражении v[i] эквивалентен оператору vector::operator[].

<p id="AutBody_Root395"><strong>21.4.1. Абстрактная точка зрения на функции-объекты</strong></p>
Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже