Таблица 7. Предикаты стандартной библиотеки
Функциональные объекты
0 1.1 1.1 2.2 3.3 4.4
Вторая форма алгоритма sort позволяет задать произвольный критерий упорядочения.
Для этого нужно передать через третий аргумент соответствующий предикат, то есть функцию или функциональный объект, возвращающие значение типа bool. Использование функции в качестве предиката было показано выше.
Использованию функциональных объектов посвящен следующий раздел.
Функциональным объектом называется объект некоторого класса,
для которого определена единственная операция вызова функции operator().
В стандартной библиотеке определены шаблоны функциональных объектов для операций сравнения, встроенных в язык C++. Они возвращают значение типа bool, то есть являются предикатами (табл. 7).
ОперацияЭквивалентный предикат (функциональный объект)
== equal_to
!= not_equal_to
> greater
< less
>= greater_equal
<= less_equal
Очевидно, что при подстановке в качестве аргумента алгоритма требуется инстанцирование этих шаблонов, например: equal_to<int>().
Вернемся к последней программе, где с помощью алгоритма sort был отсортирован вектор v1. Заменим вызов sort на следующий:
sort(v1.begin(), v1.endO, greater<double>());
В результате вектор будет отсортирован по убыванию значений его элементов.
Несколько сложней обстоит дело, когда сортировка выполняется для контейнера с объектами пользовательского класса. В этом случае программисту нужно самому позаботиться о наличии в классе предиката, задающего сортировку по умолчанию, а также (при необходимости) определить функциональные классы, объекты которых позволяют изменять настройку алгоритма sort.
В приведенной ниже программе показаны варианты вызова алгоритма sort для вектора men, содержащего объекты класса Man.
В классе Man определен предикат — операция operator<(), — благодаря которому сортировка по умолчанию будет происходить по возрастанию значений поля name.
Кроме этого, в программе определен функциональный класс Less Age, использование которого позволяет осуществить сортировку по возрастанию значений поля age.
class Man {
public:
Man (string _name, int _age):
name(_name), age(_age) { }
// предикат, задающий сортировку по умолчанию
bool operator< (const Man& m) const {
return name < m.name;
}
friend ostream& operator<< (ostream&, const Man&);
friend struct LessAge;
private:
string name;
int age;
};
ostream& operator<<(ostream& os, const Man& m) {
return os << endl << m.name << ",\t age: " << m.age;
}
// Функциональный класс для сравнения по возрасту
struct LessAge {
bool operator() (const Man& a, const Man& b) {
return a.age < b.age;
}
};
int main() {
Man ar [] = {
Man(“Mary Poppins", 36),
Man("Count Basie", 70),
Man{“Duke Ellington", 90).
Man("Joy Amore", 18)
};
int size = sizeof(ar) / sizeof(Man);
vector<Man> men(ar, ar + size);
/ / Сортировка по имени (по умолчанию)
sort(men.begin(), men.end());
print(men);
// Сортировка по возрасту
sort(men.begin(), men.end(), LessAge());
print(men);
return 0;
}