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< string > remove_words( rw, rw+5 );
vector< string >::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.