Реализация функтора Greater не является универсальной в данном случае — он «адаптирован» под нашу функцию-фильтр cofly_if (). «Адаптация» состоит в том, что мы вообще-то бинарный предикат «больше» превратили в унарный, задав один из аргументов как аргумент операции operator (), а другой — в виде поля класса. Причем мы фиксируем значение этого аргумента при создании объекта-функции. Таким образом, при вызове функтора в теле copyi f () ему передается только один аргумент — элемент контейнера. Второй инкапсулирован в функторе, и его значение зафиксировано при конструировании функтора.
Можно пойти по другому пути: написать универсальный бинарный функтор-предикат Greater и попытаться использовать его в качестве аргумента функции copyi f (). Возможная реализация представлена в листинге 12.12.
Листинг 12.12. Универсальный функтор «больше»
template<class Туре> struct Greater
{ 6ool operator()(const Туре& Left, const Туре& Right) const { return (Left > Right); }
};
Однако мы не сможем непосредственно использовать такой функтор в функции copyi f () — аргументов у него два. Тогда зачем нам «прелести» универсальности? Вообще-то в нашем конкретном случае дальнейшее обобщение выглядит лишним. Однако торопиться с выводами не следует. Этот предикат может пригодиться для других обобщенных алгоритмов (например, для сортировки), так как способен работать с любым классом, в котором реализован конструктор по умолчанию и операция «больше». Например, его вполне можно использовать для сравнения строк, если в классе строк перегружена операция operator >.
Поэтому мы все-таки попробуем задействовать этот универсальный предикат. Нам нужно каким-то образом «избавиться» от одного ир аргументов, оставив только второй. Предыдущая версия Greater подсказывает нам решение: нужно написать класс-адаптер, в котором один из аргументов предиката задается как аргумент конструктора. Таким образом, мы превратим бинарный предикат в унарный. Адаптеров должно быть два — разные для первого и второго аргументов. Кроме того, в качестве параметра, очевидно, должен передаваться и сам бинарный предикат. Реализация представлена в листинге 12.13.
Классы достаточно простые, но мы наблюдаем еще одну не совсем обычную деталь — поле-функтор, заполняемое конструктором. Соответствующий параметр передается конструктору по константной ссылке. Конечно, то же самое можно сделать и с указателем на функцию, но в объектно-ориентированном программировании все же привычнее работать с объектами.
Листинг 12.13. Адаптеры-фиксаторы аргументов бинарного предиката
template<class Predicate, class Т> class firstarg { public:
firstarg(const Predicate& P, const T& Left) : op(P), value(Left) { }
bool operator()(const T& Right) const
{ return (op(value, Right)); // реальный вид предиката
private:
Predicate op; Т value;
// предикат
// фиксированный аргумент
}:
template<class Predicate, class T> class secondarg { public:
secondarg(const Predicate& P, const T& Right) : op(P), value(Right) { }
bool operator()(const T& Left) const
{ return (op(Left, value)); // реальный вид предиката
}
private:
Predicate op; T value;
|