• глобальные функции;
• статические функции класса;
• перегруженные операторы;
• лямбда-выражения.
В Листинг 34 продемонстрировано использование предикатов различных типов.
Листинг 34. Сортировка данных с использованием предикатов различных типов
struct DBRecord // (1)
{
char firstName[50];
char lastName[50];
};
bool CompareByFirstName(const DBRecord& rec1, const DBRecord& rec2) // (2)
{
return strcmp(rec1.firstName, rec2.firstName) < 0;
}
bool CompareByLastName(const DBRecord& rec1, const DBRecord& rec2) // (3)
{
return strcmp(rec1.lastName, rec2.lastName) < 0;
}
class SortRules // (4)
{
public:
enum {SORT_ASC = 1, SORT_DESC = 2} sortDirect; // (5)
enum { SORT_FIRST_NAME = 1, SORT_LAST_NAME = 2 } sortWhat; // (6)
bool operator () (const DBRecord& rec1, const DBRecord& rec2) const // (7)
{
if (sortDirect == SORT_ASC)
{
if (sortWhat == SORT_FIRST_NAME)
{
return strcmp(rec1.firstName, rec2.firstName) < 0;
}
else
{
return strcmp(rec1.lastName, rec2.lastName) < 0;
}
}
else
{
if (sortWhat == SORT_FIRST_NAME)
{
return strcmp(rec1.firstName, rec2.firstName) > 0;
}
else
{
return strcmp(rec1.lastName, rec2.lastName) > 0;
}
}
}
};
int main()
{
DBRecord dbRecArray[10]; // (8)
//Read from database
sort_bubble(dbRecArray, 10, CompareByFirstName); // (9)
sort_bubble(dbRecArray, 10, CompareByLastName); // (10)
sort_bubble(dbRecArray, 10, [](const DBRecord& rec1, const DBRecord& rec2) // (11)
{
return strcmp(rec1.firstName, rec2.firstName) < 0;
});
sort_bubble(dbRecArray, 10, [](const DBRecord& rec1, const DBRecord& rec2) // (12)
{
return strcmp(rec1.lastName, rec2.lastName) < 0;
});
SortRules rules; // (13)
rules.sortWhat = SortRules::SORT_LAST_NAME; // (14)
rules.sortDirect = SortRules::SORT_ASC; // (15)
sort_bubble(dbRecArray, 10, rules); // (16)
}
В строке 8 объявлен массив структур, сами структуры объявлены в строке 1 (предположим, что это записи базы данных). В строке 9 и 10 происходит сортировка массива с использованием предикатов в виде внешней функции, в строках 11 и 12 – в виде лямбда-выражений.
В строке 13 объявлен предикат как экземпляр класса. Если посмотреть объявление класса (строка 4), то можно увидеть, что он позволяет осуществлять настройку правил: в строке 5 имеется переменная для настройки порядка сортировки (возрастание либо убывание), в строке 6 имеется переменная для настройки поля сортировки. В строке 7 реализован перегруженный оператор, который в соответствии с настроенными правилами вычисляет, является ли первый элемент меньше второго. В строках 14 и 15 производится настройка предиката, в строке 16 – сортировка в соответствии с заданными правилами.
4.3.4. Предикаты по умолчанию
Итак, мы рассмотрели, как с помощью предикатов реализуется операция вычисления меньшего из двух элементов. Но далеко не всегда требуется сортировать сложные структуры данных, зачастую это всего лишь обычные числовые значения. В этом случае придется объявлять предикат с тривиальной реализацией (сравнить два числа). Может также случиться, что у нас в объявлении элемента данных уже реализован перегруженный оператор сравнения, тогда в предикате придется дублировать его код. Всего этого можно избежать, если объявить предикат, который будет использоваться по умолчанию. Реализация приведена в Листинг 35.
Листинг 35. Шаблон с предикатом по умолчанию
template // (1)
struct default_less
{
bool operator()(const Data& x, const Data& y) // (2)
{
return x < y;
}
};
template > // (3)
void sort_bubble(Data* data, size_t size, Predicate less = Predicate()) // (4)
{
for (size_t i = 0; i < size – 1; i++)
{
for (size_t j = 0; j < size – i – 1; j++)
{
if (less (data[j + 1], data[j]))
{
Data temp = data[j];
data[j] = data[j + 1];
data[j + 1] = temp;
}
}
}
}
В строке 1 объявлен шаблон для структуры, реализующей предикат сравнения. В этой структуре перегружен оператор (строка 2), который возвращает результат сравнения двух аргументов. Он будет корректно работать как для чисел, так и для объектов, в которых перегружен оператор «меньше».
В строке 3 объявлен шаблон для функции сортировки. Первый параметр шаблона – это тип данных, которые необходимо сортировать, а второй параметр – это тип предиката. По умолчанию типом предиката является структура, объявленная выше, которая инстанциируется соответствующим типом данных.
Читать дальше