Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
STL5 / lab8-functors / lab8-STL-functor.doc
Скачиваний:
9
Добавлен:
10.04.2015
Размер:
259.07 Кб
Скачать

Адаптеры членов классов (1)

Рассмотрим следующий случай. Пусть имеется контейнер, содержащий объекты типа Object. Допустим, что эти объекты можно классифицировать как удовлетворяющие некоторому предикату и как неудовлетворяющие. Для проведения этой классификации используется функция-предикат bool Test(const Object& obj). Объекты неудовлетворяющие этому предикату могут быть удалены из контейнера следующим образом:

Container.erase(remove(Container.begin (), Container.end(), Test),

Container.end());

Однако возможна ситуаций, в которой требуемый предикат является методом класса:

class Object

{

public:

bool Test(void);

...

};

В этом случае хотелось бы использовать имеющийся предикат, а не переписывать его еще раз в виде функции или отдельного функтора.

Стандартные алгоритмы для вызова переданных им функций, предикатов, критериев сравнения используют следующую форму вызова Predicate(object), в то время как функция класса в данном примере должна вызывать с помощью следующей формы вызова object.Predicate(). Очевидно также, что не имеет смысла передавать алгоритму указатель на член класса в виде &Object::Test так как в этом случае правильной формой вызова было бы object.*Predicate, что тоже не соответствует используемой в алгоритмах форме вызова Predicate(object). Для адаптации описанного случая может быть использован mem_fun_ref_t.

Рассмотрим его определение и реализацию (отметим, что приведенная реализация не является стандартной, в действительности может отличаться, и приведена только для пояснения работа адаптера):

template<class Result, class T>

class mem_fun_ref_t : public unary_function<T,Result>

{

public:

explicit mem_fun_ref_t(Result (T::*Fun)()): Function(Fun) {}

Result operator()(T& x) const

{

return ((x.*Function)());

}

private:

Result(T::*Function)();

};

template<class Result, class T, class Arg>

class mem_fun1_ref_t : public binary_function<T,Arg,Result>

{

public:

explicit mem_fun1_ref_t(Result (T::*Fun)(Arg)): Function(Fun) {}

Result operator()(T& x, A y) const

{

return ((x.*Function)(y));

}

private:

Result(T::*Function)(A y);

};

template<class Result, class T>

class const_mem_fun_ref_t : public unary_function<T,Result>

{

public:

explicit const_mem_fun_ref_t(Result (T::*Fun)() const): Function(Fun) {}

Result operator()(const T& x) const

{

return ((x.*Function)());

}

private:

Result(T::*Function)() const;

};

template<class Result, class T, class Arg>

class const_mem_fun1_ref_t : public binary_function<T,Arg,Result>

{

public:

explicit const_mem_fun1_ref_t(Result (T::*Fun)(Arg) const): Function(Fun) {}

Result operator()(const T& x, A y) const

{

return ((x.*Function)(y));

}

private:

Result(T::*Function)(A y) const;

};

mem_fun_ref_t используется для адаптации методов классов без аргументов в функторы принимающие один аргумент (этим аргументом является объект, к которому будет применен метод), а mem_fun1_ref_t используется для адаптации методов классов с одним аргументом в функторы принимающие два аргумента (первым аргументов является объект, к которому будет применен метод, а вторым аргументом функтора является аргумент передаваемый вызываемому методу класса)

Основная идея заложенная в классе mem_fun_ref_t – конструктору объекта передается указатель на метод класса соответствующего типа (адаптируемый метод), который сохраняется во внутренней переменной; при вызове функтора оператору operator() передается ссылка на объект, к которому должен быть применен адаптируемый метод (вызов функтора выполняется с использование functor(object) формы вызова); внутри operator() вызове преобразуется в вид object.*Function(), собственно вызов адаптируемого метода. Аналогично функционирует класс mem_fun1_ref_t, отличие заключается только в дополнительном параметре передаваемом в функтор и метод класса.

Отличие mem_fun_ref_t и mem_fun1_ref_t от const_mem_fun_ref_t и const_mem_fun1_ref_t заключается в том, что const варианты предназначены для адаптации константных методов классов (методов, которые не изменяют объект), а не const варианты адаптируют неконстантные методы классов (методы, которые изменяют объект).

В STL определена вспомогательная функция для создания объектов mem_fun_ref_t, mem_fun1_ref_t, const_mem_fun_ref_t и const_mem_fun1_ref_t

template<class Result, class T> inline

mem_fun_ref_t<Result,T> mem_fun_ref(Result (T::*p)())

{

return (mem_fun_ref_t<Result,T>(p));

}

template<class Result, class T, class Arg> inline

mem_fun1_ref_t<Result,T,Arg> mem_fun_ref(Result (T::*p)(Arg))

{

return (mem_fun1_ref_t<Result,T,Arg>(p));

}

template<class Result, class T> inline

const_mem_fun_ref_t<Result,T> mem_fun_ref(Result (T::*p)() const)

{

return (const_mem_fun_ref_t<Result,T>(p));

}

template<class Result, class T, class Arg> inline

const_mem_fun1_ref_t<Result,T,Arg> mem_fun_ref(Result (T::*p)(Arg) const)

{

return (const_mem_fun1_ref_t<Result,T,Arg>(p));

}

Обратим внимание на то, что для создания объекта нужного класса может быть использована одна функция, вызов которого имеет вид mem_fun_ref(&Class::method); при этом нет необходимости правильно указывать объект, а также параметры шаблона. Если быть точным, для создания объекта используется не одна функция, а один из четырех перегруженных вариантов.

Теперь фрагмент удаления объектов из списка будет выглядеть следующим образом:

vector<Object> VecOfObjects;

...

VecOfObjects.erase(remove((VecOfObjects.begin(), ListOfObjects.end(),

mem_fun_ref(&Object::test)), ListOfObjects.end());

Ниже приведен пример2 использования адаптеров методов класса:

#include <iostream>

#include <algorithm>

#include <functional>

#include <vector>

#include <string>

using namespace std;

class Person

{

public:

Person(const string& name, int age) : name(name), age(age) {}

// Константный метода класса без аргументов

Соседние файлы в папке lab8-functors