Стандартные алгоритмы также используют функциональные объекты, или функторы. Функциональный объект — это класс, который переопределяет operator() так, что его можно вызвать как функцию. Функтор, который возвращает bool (и не поддерживает состояния, и, следовательно, называется чистым (pure), называется предикатом (predicate), и он является еще одной обычной функциональной особенностью стандартных алгоритмов. Обычно предикат принимает один или два аргумента: если он принимает один аргумент, то это унарный предикат, а если два — то бинарный предикат. Для краткости я при демонстрации объявлений функций использую сокращения, приведенные в табл. 7.2.

Табл. 7.2. Типы функторов

Имя типа Описание
UnPred Унарный предикат. Принимает один аргумент и возвращает bool
BinPred Бинарный предикат. Принимает два аргумента и возвращает bool
UnFunc Унарная функция. Принимает один аргумент и возвращает некое значение
BinFunc Бинарная функция. Принимает два аргумента и возвращает некое значение

В большинстве случаев там, где требуется аргумент в виде функтора, может использоваться указатель на функцию. При использовании термина «функтор» я также подразумеваю указатель на функцию, если не указано иного.

7.1. Перебор элементов контейнера

Проблема

Имеется диапазон итераторов — скорее всего, из стандартного контейнера — и стандартные алгоритмы не удовлетворяют вашим требованиям, так что вам требуется выполнить итерации самостоятельно.

Решение

Для доступа к элементам контейнера и перехода от одного элемента к другому используйте iterator или const_iterator. В стандартной библиотеке алгоритмы и контейнеры взаимодействуют с помощью итераторов, и одной из базовых идей стандартных алгоритмов является то, что они избавляют вас от необходимости непосредственного использования итераторов, за исключением тех случаев, когда вы пишете собственный алгоритм. И даже в этом случае вы должны понимать различные типы итераторов с тем, чтобы эффективно использовать стандартные алгоритмы и контейнеры. Пример 7.1 представляет некоторые простые способы использования итераторов.

Пример 7.1. Использование итераторов с контейнерами

#include <iostream>

#include <list>

#include <algorithm>

#include <string>

using namespace std;

static const int ARRAY_SIZE = 5;

template<typename T, typename FwdIter>

FwdIter fixOutliersUBound(FwdIter p1,

 FwdIter p2, const T& oldVal, const T& newVal) {

 for ( ; p1 != p2; ++p1) {

  if (greater<T>(*p1, oldVal)) {

   *p1 = newVal;

  }

 }

}

int main() {

 list<string> lstStr;

 lstStr.push_back('Please');

 lstStr.push_back('leave');

 lstStr.push_back('a');

 lstStr.push_back('message');

 // Создать итератор для последовательного перебора элементов списка

 for (list<string>::iterator p = lstStr.begin();

  p != lstStr.end(); ++p) {

  cout << *p << endl;

 }

 // Или можно использовать reverse_iterator для перебора от конца

 // к началу, rbegin возвращает reverse_iterator, указывающий

 // на последний элемент, a rend возвращает reverse_iterator, указывающий

 // на один-перед-первым.

 for (list<string>::reverse_iterator p = lstStr.rbegin();

  p != lstStr.rend(); ++p) {

  cout << *p << endl;

 }

 // Перебор диапазона элементов

 string arrStr[ARRAY_SIZE] = {'My', 'cup', 'cup', 'runneth', 'over'};

 for (string* p = &arrStr[0];

  p != &arrStr[ARRAY_SIZE]; ++p) {

  cout << *p << endl;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату