|
6.4. Объекты-функции. Предикаты6.4.1. Объекты-функции. Пример 6.5 (использование объектов-функций)Объекты-функции – это объекты, у которых перегружен оператор вызова функций operator(). В библиотеке STL уже определено несколько полезных арифметических и других объектов-функций (описание в файле <functional>):
Рассмотрим пример с отрицанием всех элементов вектора. Можно выполнить этот пример с помощью цикла, а можно сделать намного проще с использованием алгоритма transform и стандартной функции negate. vector<int> v; vector<int>::iterator it=v.begin(); while(it != v.end()) { *it = -(*it); it++; } // то же самое с использованием объекта-функции negate transform(v.begin(),v.end(), v.begin(), negate<int>()); // вывод контейнера на экран copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); Алгоритмы (описание в файле < algorithm>) позволяют выполнять некоторые типовые действия надо контейнерами с использованием объектов-функций стандартной библиотеки или своих объектов-функций. Подробно алгоритмы, функции, и другие возможности библиотеки STL приводятся в Приложении 5. Стандартные алгоритмы можно использовать и для ввода и вывод контейнера на экран. При чтении ввод происходит до ввода первого не числового символа. Программисты могут определить свои объекты-функции, которые могут быть наследниками от стандартных. В объектах-функциях обязательно должен быть перегружен оператор вызова функции (), в конструкторе могут задаваться необходимые параметры, или он может быть пустым (см.пример 6.5). Функции могут быть двух типов:
Для унарных функций перегруженный оператор вызова функции должен содержать один параметр, в бинарных – два параметра. Иногда нужно преобразовать бинарную функцию в унарную, например умножение – бинарная функция, нужны два элемента, а мы хотим умножить все элементы контейнера на одно и то же число. Для этого можно использовать функцию bind2nd. Функция binder2nd – преобразует бинарную функцию в унарную, и принимает второй аргумент как параметр бинарной функции (описание в файле <functional>) // умножение каждого элемента на 2 transform (v.begin(), v.end(), v.begin(), bind2nd(multiplies<int>(), 2)); Пример 6.5. Использование объектов-функций///////////////////////////////////////////////////////////////////////////// // Программирование на языке высокого уровня. Основы языка С++ // Пример 6.5. Использование объектов-функций // // http://aco.ifmo.ru/el_books/programming // Университет ИТМО ///////////////////////////////////////////////////////////////////////////// #include <functional> #include <algorithm> #include <vector> #include <iostream> #include <iterator> using namespace std; ///////////////////////////////////////////////////////////////////////////// // создание объекта-функции для заполнения случайными числами // функция Rand - шаблон, наследник от стандартной функции unary_function // параметры шаблона: PAR - тип данных, void - возвращаемое значение оператора () template <class PAR> class Rand : public unary_function<PAR, void> { // диапазон случайных чисел PAR m_min, m_max; public: // конструктор, в котором задается диапазон случайных чисел Rand(PAR min, PAR max) : m_min(min), m_max(max) { } // перегруженный оператор вызова функции, в котором число value заполняется случайным числом void operator() (PAR& value) { value=(PAR)(rand()*(m_max-m_min))/RAND_MAX+m_min; } }; ///////////////////////////////////////////////////////////////////////////// // тестирование объектов-функций STL - negate, ввод-вывод void main() { vector<int> v; // чтение контейнера из потока ввода (до первого не числового символа) copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(v)); // вывод контейнера на экран copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout<<endl; // использование объекта-функции negate transform(v.begin(),v.end(), v.begin(), negate<int>()); copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout<<endl; // заполнение контейнера случайными числами при помощи объекта-функции Rand for_each(v.begin(), v.end(), Rand<int>(-10, 10)); copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout<<endl; // умножение каждого элемента на 2, // использование стандартной бинарной функции multiplies, // преобразованной в унарную при помощи функции bind2nd transform (v.begin(), v.end(), v.begin(), bind2nd(multiplies<int>(), 2)); copy (v.begin(), v.end(),ostream_iterator<int>(cout, " ")); cout<<endl; } ///////////////////////////////////////////////////////////////////////////// 6.4.2. Предикаты. Пример 6.6 (использование предикатов)Предикаты позволяют без изменения шаблона изменять критерии сравнения элементов контейнера и другие подобные действия. У предикатов объект-функция возвращает значение bool. В файле <functional> уже определено несколько полезных предикатов:
Например, стандартный алгоритм сортировки сортирует по возрастанию, если мы хотим сделать сортировку по убыванию – можно использовать предикат greater: // сортировка в порядке убывания sort(v.begin(), v.end(), greater<int>()); Можно определять свои предикаты, как наследники от стандартных объектов-функций. Пример 6.6. Использование предикатов///////////////////////////////////////////////////////////////////////////// // Программирование на языке высокого уровня. Основы языка С++ // Пример 6.6. Использование предикатов // // http://aco.ifmo.ru/el_books/programming // Университет ИТМО ///////////////////////////////////////////////////////////////////////////// #include <functional> #include <numeric> #include <algorithm> #include <vector> #include <iostream> #include <iterator> using namespace std; ///////////////////////////////////////////////////////////////////////////// // создание объекта-функции для заполнения случайными числами // функция Rand - шаблон, наследник от стандартной функции unary_function // параметры шаблона: PAR - тип данных, void - возвращаемое значение оператора () template <class PAR> class Rand : public unary_function<PAR, void> { // диапазон случайных чисел PAR m_min, m_max; public: // конструктор, в котором задается диапазон случайных чисел Rand(PAR min, PAR max) : m_min(min), m_max(max) { } // перегруженный оператор вызова функции, в котором число value заполняется случайным числом void operator() (PAR& value) { value=(PAR)(rand()*(m_max-m_min))/RAND_MAX+m_min; } }; ///////////////////////////////////////////////////////////////////////////// // создание объекта-функции определения попадания числа в диапазон // функция InRange - шаблон, наследник от стандартной функции unary_function // параметры шаблона: int - тип данных, bool - возвращаемое значение оператора () class InRange : public unary_function<int, bool> { // диапазон чисел int m_left, m_right; public: // конструктор, в котором задается диапазон InRange(int left, int right) : m_left(left), m_right(right) {} // перегруженный оператор вызова функции, в котором определяется // попадание числа value в диапазон от m_left до m_right bool operator() (const int& value) { return (value>m_left && value<m_right); } }; ///////////////////////////////////////////////////////////////////////////// // тестирование предикатов void main() { vector<int> v(10); // заполнение контейнера случайными числами при помощи объекта-функции Rand for_each(v.begin(), v.end(), Rand<int>(-10, 10)); copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout<<endl; // сортировка с использованием предиката greater sort(v.begin(), v.end(), greater<int>()); copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout<<endl; // использование InRange для подсчета количества элементов в диапазоне от 0 до 10 cout << count_if(v.begin(), v.end(), InRange(0, 10)); cout<<endl; } ///////////////////////////////////////////////////////////////////////////// |