Листинг 12.6. Функция-фильтр с параметром-функцией
template < class.Inputlterator, class Outputlterator, class T
>
void copy_if( Inputlterator first, Inputlterator last, Outputlterator result, bool f(const T &a, const T &b), const T &v
)
{ for ( ; first != last; ++first) if (f(v, *first)) { *result = *first; ++result; } return;
}
// функции-предикаты
template <class T>
bool lessf(const T &a, const T &b)
{ return (a<b); }
bool greatef(const int &a, const int &b) { return a > b; } // главная функция int main()
{ int a[10] = { 1,2,3,4,5,6,7,8,9,0}; int b[10] ={0};
copy_if(a, a*10, b, lessf<int>, 5); for(int i =0; i < 10; ++i)
cout << b[i] << • '; cout << endl;
copy_if(a, a+10, b, greatef, 7); for(int i =0; i < 10; ++i)
cout << b[i] << ' '; cout << endl; getchar();
return EXIT_SUCCESS;
}
Эта программа выводит на экран следующее: 1
6789000000 1234560000
Первая строка — это результат вызова: copy_if(a, a+10, b, lessf<int>, 5); Вторая строка соответствует вызову: copy_if(a, a+10, b, greatef, 7);
Как видите, наша обобщенная функция-фильтр прекрасно работает и с обычной функцией, и с шаблоном функции. Аргумент шаблона должен совпадать с типом элементов массива. Попробуем задать другой тип, например:
copy_if(a', a+10, b, lessf<double>, 5);
В результате возникает ошибка трансляции — вспомним, что автоматическое преобразование типов в шаблонах не работает.
Разберемся теперь в достоинствах и недостатках данного подхода. Очевидным достоинством является дальнейшее обобщение функции-фильтра: мы теперь можем задать ей в качестве параметра любой бинарный предикат.
Однако обобщения на этом не заканчиваются. На мой взгляд, тип передаваемой функции излишне «жестко» зафиксирован. Кроме того, последний параметр тоже выглядит лишним — именно он придает «жесткость» типу функции-предиката. Стоит подумать, чтобы сократить количество параметров до четырех — ведь нужен только входной контейнер, выходной контейнер и функция-предикат для отбора элементов. Рассмотрим, как это можно сделать. Параметр, записанный следующим образом, интерпретируется как указатель на функцию:
bool f(const Т &а. const Т &b)
Можно записать этот параметр явно, как указатель:
bool (*f)(const Т &а, const Т &b)
Этот вариант эквивалентен предыдущей записи. Последний вариант наводит на мысль о применении ключевого слова typedef:
typedef bool (*Predicate)(const T &a, const T &b);
Тип Predicate можно указать в качестве типа параметра-предиката. Однако значительно лучше написать аналогичный параметр шаблона:
template < class Inputlterator, class Outputlterator, class Predicate, class T
>
void copy_if( Inputlterator first, Inputlterator last, Outputlterator result, Predicate function, const T &v
)
Такая запись разрешается, так как параметром шаблона может быть указатель на функцию (см. п. п. 14.1/4 в [1]).
Теперь подумаем, какой должна быть эта функция-предикат. Хотя это выглядит парадоксальным, но унарный предикат делает нашу функцию-фильтр более универсальной и позволяет избавиться от последнего параметра (листинг 12.7). |