// проверку, он помечается как "плохой"
Допустим, у нас имеется контейнер объектов Widget
:
vector
Для проверки всех объектов Widget
в контейнере vw
можно воспользоваться алгоритмом for_each
:
for_each(vw.begin, vw.end, test); // Вариант 1 (нормально компилируется)
Но представьте, что test
является функцией класса Widget
, а не внешней функцией (то есть класс Widget
сам обеспечивает проверку своих объектов):
class Widget {
public:
…
void test; // Выполнить самопроверку. Если проверка
… // завершается неудачей, объект помечается
}; // как "плохой"
В идеальном мире мы могли бы воспользоваться for_each
для вызова функции Widget::test
всех объектов вектора vw
:
for_each(vw.begin, vw.end,
&Widget::test); // Вариант 2 (не компилируется!)
Более того, если бы наш мир был действительно идеальным, алгоритм for_each
мог бы использоваться и для вызова Widget::test
в контейнере указателей Widget*
:
list
// на объекты Widget
for_each(lpw.begin, lpw.end, // Вариант 3 (не компилируется!)
&widget::test);
Но подумайте, что должно было бы происходить в этом идеальном мире. Внутри функции for_each
в варианте 1 вызывается внешняя функция, поэтому должен использоваться синтаксис 1. Внутри вызова for_each
в варианте 2 следовало бы использовать синтаксис 2, поскольку вызывается функция класса. А внутри функции for_each
в варианте 3 пришлось бы использовать синтаксис 3, поскольку речь идет о функции класса и указателе на объект. Таким образом, нам понадобились бы for_each
— разве такой мир можно назвать идеальным?
В реальном мире существует только одна версия for_each
. Нетрудно представить себе возможную ее реализацию:
template
Function for_each(InputIterator begin, InputIterator end, Function f) {
while (begin != end) f(*begin++);
}
Жирный шрифт используется для выделения того, что при вызове for_each
используется синтаксис 1. В STL существует всеобщее правило, согласно которому функции и объекты функций всегда вызываются в первой синтаксической форме (как внешние функции). Становится понятно, почему вариант 1 компилируется, а варианты 2 и 3 не компилируются — алгоритмы STL (в том числе и for_each
) жестко закодированы на использование синтаксиса внешних функций, с которым совместим только вариант 1.
Теперь понятно, для чего нужны функции mem_fun
и mem_fun_ref
. Они обеспечивают возможность вызова функций классов (обычно вызываемых в синтаксисе 2 и 3) при помощи синтаксиса 1.
Принцип работы mem_fun
и mem_fun_ref
прост, хотя для пущей ясности желательно рассмотреть объявление одной из этих функций. В действительности они представляют собой шаблоны функций, причем существует несколько вариантов mem_fun
и mem_fun_ref
для разного количества параметров и наличия-отсутствия константности адаптируемых ими функций классов. Одного объявления вполне достаточно, чтобы разобраться в происходящем:
template
mem_fun_t
mem_fun(R(C::*pmf)); // R - тип возвращаемого значения функции.
// на которую ссылается указатель
Функция mem_fun
создает указатель pmf
на функцию класса и возвращает объект типа mem_fun_t
. Тип представляет собой класс функтора, содержащий указатель на функцию и функцию operator
, которая по указателю вызывает функцию для объекта, переданного operator
. Например, в следующем фрагменте:
list
…
for_each(lpw.begin, lpw.end,
mem_fun(&Widget::test)); // Теперь нормально компилируется
При вызове for_each
передается объект типа mem_fun_t
, содержащий указатель на Widget::test
. Для каждого указателя Widget*
в lpw
алгоритм for_each
«вызывает» объект mem_fun_t
с использованием синтаксиса 1, а этот объект непосредственно вызывает Widget::test
для указателя Widget*
с использованием синтаксиса 3.