СокращениеЗначение
InInput iterator (Итератор ввода)
OutOutput iterator (Итератор вывода)
FwdForward iterator (Однонаправленный итератор)
BidBidirectional iterator (Двунаправленный итератор)
RandRandom-access iterator (Итератор произвольного доступа)

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

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

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

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

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

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

Решение

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

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

#include

#include

#include

#include

using namespace std;

static const int ARRAY_SIZE = 5;

template

FwdIter fixOutliersUBound(FwdIter p1,

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

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

  if (greater(*p1, oldVal)) {

   *p1 = newVal;

  }

 }

}

int main() {

 list lstStr;

 lstStr.push_back("Please");

 lstStr.push_back("leave");

 lstStr.push_back("a");

 lstStr.push_back("message");

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

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

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

  cout << *p << endl;

 }

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

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

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

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

 for (list::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];

Перейти на страницу:

Похожие книги