double xSum;
double ySum;
};
list lp;
…
Point avg = for_each(lp.begin(), lp.end(), PointAverage()). result();
Лично я предпочитаю обобщать интервальные данные при помощи accumulate
, поскольку мне кажется, что этот алгоритм наиболее четко передает суть происходящего, однако foreach
тоже работает, а вопрос побочных эффектов для for_each
не так принципиален, как для accumulate
. Словом, для обобщения интервальных данных могут использоваться оба алгоритма; выберите тот, который вам лучше подойдет.
Возможно, вас интересует, почему у for_each
параметр-функция может иметь побочные эффекты, а у accumulate
— не может? Представьте, я бы тоже хотел это знать. Что ж, дорогой читатель, некоторые тайны остаются за пределами наших познаний. Чем accumulate
принципиально отличается от for_each
? Пока я еще не слышал убедительного ответа на этот вопрос.
Функции, функторы и классы функций
Нравится нам это или нет, но функции и представляющие их объекты (функторы) занимают важное место в STL. Они используются ассоциативными контейнерами для упорядочения элементов, управляют работой алгоритмов типа find_if
, конструкции for_each
и transform
без них теряют смысл, а адаптеры типа not1
и bind2nd
активно создают их.
Да, функторы и классы функторов встречаются в STL на каждом шагу. Встретятся они и в ваших программах. Умение создавать правильно работающие функторы абсолютно необходимо для эффективного использования STL, поэтому большая часть этой главы посвящена одной теме — как добиться того, чтобы функторы работали именно так, как им положено работать в STL. Впрочем, один совет посвящен другой теме и наверняка пригодится тем, кто задумывался о необходимости включения в программу вызовов ptr_fun
, mem_fun
и mem_fun_ref
. При желании начните с совета 41, но пожалуйста, не останавливайтесь на этом. Когда вы поймете, для чего нужны эти функции, материал остальных советов поможет вам наладить правильное взаимодействие ваших функторов с ними и с STL в целом.
Совет 38. Проектируйте классы функторов для передачи по значению
Ни C, ни C++ не позволяют передавать функции в качестве параметров других функций. Вместо этого разрешается передавать указатели на функции. Например, объявление стандартной библиотечной функции qsort
выглядит следующим образом:
void qsort(void *base, size_t nmemb, size_t size,
int (*cmpfcn)(const void*, const void*));
В совете 46 объясняется, почему вместо функции qsort
обычно рекомендуется использовать алгоритм sort
, но дело не в этом. Нас сейчас интересует объявление параметра cmpfcn
функции qsort
. При внимательном анализе становится ясно, что аргумент cmpcfn
, который является указателем на функцию, копируется (то есть передается по значению) из точки вызова в функцию qsort
. Данный пример поясняет правило, соблюдаемое стандартными библиотеками C и C++, — указатели на функции должны передаваться по значению.
Объекты функций STL создавались по образцу указателей на функции, поэтому в STL также действует правило, согласно которому объекты функций передаются по значению (то есть копируются). Вероятно, это правило лучше всего демонстрирует приведенное в Стандарте объявление алгоритма for_each
, который получает и передает по значению объекты функций:
template
Function// Возврат по значению
for_each(InputIterator first, InputIterator last,
Function f);// Передача по значению
Честно говоря, передача по значению не гарантирована полностью, поскольку вызывающая сторона может явно задать типы параметров в точке вызова. Например, в следующем фрагменте for_each
получает и возвращает функторы по ссылке:
class DoSomething:
public unary_function{ // Базовый класс описан
void operator()(int x){…} // в совете 40
};
typedef deque::iterator DequeIntIter; // Вспомогательное определение
deque di;
…
DoSomething d; // Создать объект функции
…
for_each< DequeIntIter, // Вызвать for_each с типами
DoSomethng&>(di.begin(), // параметров DequeIntIter
di.end(), // и DoSomething& в результате
d); // происходит передача
Читать дальше