// проверку, он помечается как "плохой"
Допустим, у нас имеется контейнер объектов 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.