Выбрать главу

string st1( "shakespeare" );

string st2( "marlowe" );

// вызывается lt.operator()( st1, st2 );

bool is_shakespeare_less = lt( st1, st2 );

Ниже показана исправленная функция process_vocab(), в которой алгоритму

stable_sort() передается безымянный объект-функция LessThan():

void process_vocab( vectortextwords, allocator *pvec )

{

// ...

stable_sort( texts.begin(), texts.end(), LessThan() );

// ...

}

Внутри stable_sort() перегруженный оператор вызова подставляется в текст программы как встроенная функция. (В качестве третьего аргумента stable_sort() может принимать как указатель на функцию less_than(), так и объект класса LessThan, поскольку аргументом является параметр-тип шаблона. Подробнее об объектах-функциях мы расскажем в разделе 12.3.)

Вот результат применения stable_sort() к вектору texts:

a i

as at by he in is it no

of on so to and but for has

her him its not now one red row

she sky the you asks bird blue coat

dark each emma fear grow hair held home

life like long mean more puts same says

star such tell that time what when wind

with your alice alive blows daddy falls fiery

lands leave looks quite rises shush shyly sight

still stone tells there thing trees watch almost

either flight houses night, ancient becomes bounded calling

distant flowing heaven, magical passion through unravel untamed

wanting darkened eternity beautiful darkening immensity journeying alternately

immeasurable inexpressibly

Подсчитать число слов, длина которых больше шести символов, можно с помощью обобщенного алгоритма count_if() и еще одного объекта-функции – GreaterThan. Этот объект чуть сложнее, так как позволяет пользователю задать размер, с которым производится сравнение. Мы сохраняем размер в члене класса и инициализируем его с помощью конструктора (по умолчанию – значением 6):

#include iostream

class GreaterThan {

public:

GreaterThan( int size = 6 ) : _size( size ){}

int size() { return _size; }

bool operator()( const string & s1 )

{ return s1.size() 6; }

private:

int _size;

};

Использовать его можно так:

void process_vocab( vectortextwords, allocator *pvec )

{

// ...

// подсчитать число строк, длина которых больше 6

int cnt = count_if( texts.begin(), texts.end(),

GreaterThan() );

cout "Number of words greater than length six are "

cnt endl;

// ...

}

Этот фрагмент программы выводит такую строку:

Number of words greater than length six are 22

Алгоритм remove() ведет себя аналогично unique(): он тоже не изменяет размер контейнера, а просто разделяет элементы на те, что следует оставить (копируя их по очереди в начало контейнера), и те, что следует удалить (перемещая их в конец контейнера). Вот как можно воспользоваться им для исключения из коллекции слов, которые мы не хотим сохранять:

void process_vocab( vectortextwords, allocator *pvec )

{

// ...

static string rw[] = { "and", "if", "or", "but", "the" };

vector&lt string &gt remove_words( rw, rw+5 );

vector&lt string &gt::iterator it2 = remove_words.begin();

for ( ; it2 != remove_words.end(); ++it2 ) {

// просто для демонстрации другой формы count()

int cnt = count( texts.begin(), texts.end(), *it2 );

cout cnt " instances removed: "

(*it2) endl;

texts.erase(

remove(texts.begin(),texts.end(),*it2 ),

texts.end()

);

}

// ...

}

Результат применения remove():

1 instances removed: and

0 instances removed: if

0 instances removed: or

1 instances removed: but

1 instances removed: the

Теперь нам нужно распечатать содержимое вектора. Можно обойти все элементы и вывести каждый по очереди, но, поскольку при этом обобщенные алгоритмы не используются, мы считаем такое решение неподходящим. Вместо этого проиллюстрируем работу алгоритма for_each() для вывода всех элементов вектора. for_each() применяет указатель на функцию или объект-функцию к каждому элементу контейнера из диапазона, ограниченного парой итераторов. В нашем случае объект-функция PrintElem копирует один элемент в стандартный вывод:

class PrintElem {

public:

PrintElem( int lineLen = 8 )

: _line_length( lineLen ), _cnt( 0 )

{}

void operator()( const string &elem )

{

++_cnt;

if ( _cnt % _line_length == 0 )

{ cout '\n'; }

cout elem "";

}

private:

int _line_length;

int _cnt;

};

void process_vocab( vector *pvec )

{

// ...

for_each( texts.begin(), texts.end(), PrintElem() );

}

Вот и все. Мы получили законченную программу, для чего пришлось лишь последовательно записать обращения к нескольким обобщенным алгоритмам. Для удобства мы приводим ниже полный листинг вместе с функцией main() для ее тестирования (здесь используются специальные типы итераторов, которые будут обсуждаться только в разделе 12.4). Мы привели текст реально исполнявшегося кода, который не полностью удовлетворяет стандарту C++. В частности, в нашем распоряжении были лишь устаревшие реализации алгоритмов count() и count_if(), которые не возвращают результат, а требуют передачи дополнительного аргумента для вычисленного значения. Кроме того, библиотека iostream отражает предшествующую принятию стандарта реализацию, в которой требуется заголовочный файл iostream.h.