После описанной модификации первоначального кода у нас остается одна проблема: как выполнять операции сравнения для нечисловых данных, например, структур? Ведь алгоритм не знает, да и не должен знать, по каким правилам нужно их сравнивать. Выход очевидный – делегировать эти операции создателю данных. Для этого будем использовать обратный вызов «вычисление по запросу» (п. 1.2.2). Параметрами вызова будут экземпляры данных, а возвращать он будет результат сравнения. Оформленный таким образом вызов называется предикатом.

Предикат – это выражение, принимающее одну или более величину и возвращающее результат булевого типа.

Объявим предикат как дополнительный параметр шаблона (Листинг 33).

Листинг 33. Шаблон с объявлением предиката

template               // (1)

void sort_bubble(Data* data, size_t size, Predicate less) // (2)

{

  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])) // (3)

      {

        Data temp = data[j];

        data[j] = data[j + 1];

        data[j + 1] = temp;

      }

    }

  }

}

По сравнению с предыдущим кодом из Листинг 32 изменения здесь следующие: в объявлении шаблона (строка 1) объявлен дополнительный параметр – предикат, в функции шаблона (строка 2) предикат объявляется как дополнительный входной параметр, в строке 3 вместо операции сравнения происходит вычисление предиката.

В качестве предикатов могут использоваться:

• глобальные функции;

• статические функции класса;

• перегруженные операторы;

• лямбда-выражения.

В Листинг 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)

Перейти на страницу:

Похожие книги