Операций выбора члена класса две, однако мы реализуем один класс-адаптер1 для операции . *. Пойдем по пути некоторого обобщения наших классов-адаптеров. Сначала напишем классы-шаблоны свойств функций-предикатов (листинг 12.18).
Листинг 12.18. Классы-шаблоны свойств функций-предикатов
template<class Arg>
struct unarypredicate // унарный предикат
{ typedef Arg argument__type; };
template<class Argl, class Arg2>
struct binarypredicate // бинарный предикат
{ typedef Argl first_argument_type;
typedef Arg2 . second_argument_type;
};
Естественно, можно было и тип результата сделать параметром шаблона, однако в данном случае это не очень существенно. Гораздо важнее то, что мы можем теперь наследовать от этих шаблонов! Например, приведенный в листинге 12.12 обобщенный функтор Greater можно написать как наследник от класса бинарного предиката (листинг 12.19).
Листинг 12.19. Наследование от класса свойств
template<class Туре>
struct Greater: public binarypredicate<Type, Type> { bool operator()(const Type& Left, const Type& Right) const { return (Left > Right): }
};
Наследование позволяет упростить шаблон класса-фиксатора, оставив только один параметр шаблона — функцию-предикат (листинг 12.20). Тип аргументов предиката, который передавался как второй аргумент шаблона, мы «позаимствуем» у базового класса свойств. Естественно, упрощается и функция-оболочка.
Листинг 12.20. Класс-фиксатор — наследник от класса свойств
template<class Predicate>
class secondarg: public // наследование от унарного предиката
unarypredicate<typename Predicate::first_argument_type>
{ public:
typedef unarypredicate<typename Predicate::first_argument_type> Base:
typedef typename Base::argument_type argument_type;
// конструктор
secondarg(const Predicate& P,
const typename Predicate::second_argument_type& Right) : op(P), value(Right) { } bool operator()(argument_type Left)
{ return (op(Left, value)): } // вызываемый предикат private:
Predicate op:
typename Predicate: :second_argument__type value:
};
// функция-оболочка
template<class Predicate, class Type>
inline
secondarg<Predicate>
bindright(const Predicate& P, const Type& Right) { typename Predicate::second_argument_type value(Right); return (secondarg<Predicate>(P, value.)):
Обратите внимание на важнейшую особенность: класс-фиксатор наследует от класса унарного предиката, а в качестве параметра получает бинарный предикат.
Теперь напишем сам класс-адаптер для указателя на метод и функцию-оболочку. Указатель на метод, естественно, является полем этого класса, а сам класс наследует от класса бинарного предиката (листинг 12.21).
Листинг 12.21. Класс-адаптер для указателя на метод — наследник класса свойств template <typename class, typename T>
class ReferenceToMethod: public binarypredicate<class, T> { public:
explicit ReferenceToMethod(bool (class::*pm)(T v))
: pmethod(pm) { }
bool operator()(class Obj, T v)
{ return ((Obj.*pmethod)(v)); } // вызов метода
private:
bool (class::*pmethod)(T v); // указатель на метод
};
template<class class, class T> inline
ReferenceToMethod<class, T> memfun(bool (class::*Pm)(T v)) { return (ReferenceToMethod<class, T>(Pm)): }
Конструктор получает в качестве параметра указатель на метод и заполняет поле класса. Операция вызова функции operatorO принимает объект и аргумент метода, вызывая метод через инициализированный конструктором указатель на метод. Функция-оболочка автоматизирует вывод параметров шаблона.
Использовать эти классы и функции-оболочки можно так:
int а[10] = { 1,2,3,4,5.6,7.8.9.0}; int b[10] = {0}:
copy_if(a, a+10, b, bindright(memfun(&Constant:.greater), 5)): for(int i = 0: i < 10; ++i) cout << b[i] << 1 '; cout << endl;
Мощь аппарата функторов не может не вызывать изумления! Посмотрите, на месте единственного параметра-функтора фактически заданы 4 аргумента:
1. Указатель на метод Constant: : greater.
2. Целая константа 5.
3. Функция memf un ().
4. Функция bindright().
Попробуйте-ка реализовать аналогичную функциональность, использовав указатели на функции!
Обратите внимание на то, что класс-адаптер ReferenceToMethod наследует от бинарного предиката, хотя его аргументы в теле класса никак не используются. В данном случае без наследования обойтись никак нельзя, поскольку «последней инстанцией» является класс-фиксатор, который, будучи наследником, задействует аргументы предиката. В классе-адаптере можно было бы написать несколько |