В строке 1 объявлена общая специализация шаблона, параметрами выступают адрес получателя Address, предикат для сравнения AddressCompare и сигнатура распределяющей функции Function. Реализация здесь отсутствует, поскольку для каждой сигнатуры требуется отдельная специализация – аналогично настройке сигнатуры для универсального аргумента (п. 4.5.2).

В строке 2 объявлена частичная специализация, в которой дополнительно представлены параметр для возвращаемого значения Return и пакет параметров ArgumentList для аргументов функции. В строке 3 объявлен класс, который специализируется сигнатурой из указанных параметров.

В строке 4 объявлен шаблон метода для добавления получателя, который принимает адрес address, вызываемый объект object и добавляет их в контейнер. В строке 5 объявлен метод для удаления получателя. Оба метода работают с контейнером, который объявлен в строке 10. Контейнер объявлен как std::map, ключом является адрес, а значением – объект std::function с заданной сигнатурой.

В строке 6 объявлен перегруженный оператор, который осуществляет распределение вызовов, т. е. является распределяющей функцией. Он пробегает по всем элементам контейнера и осуществляет вызов в соответствии с списком аргументов, типы которых задаются в пакете параметров шаблона класса. Поскольку мы используем адресное распределение, т. е. предполагается, что вызов попадает только одному получателю, то мы операторе можем вернуть результат вызова.

В строке 7 происходит поиск получателя по адресу. Если получатель найден, то происходит вызов объекта (строка 8). Если получатель не найден, то генерируется исключение (строка 9), иначе какой результат нам возвратить?

<p>5.7.3. Использование адресного распределения</p>

Пример использования адресного распределения приведен в Листинг 85.

Листинг 85. Использование адресного распределения

struct FO

{

  int operator() (int eventID)

  {

    return 10;

  }

};

int ExternalHandler(int eventID)

{

  return 0;

}

struct ReceiverAddress  // (1)

{

  ReceiverAddress(int idGroup = 0, int idNumber = 0)

  {

    group = idGroup; number = idNumber;

  }

  int group;

  int number;

};

template<>

struct std::less  // (2)

{

  bool operator() (const ReceiverAddress& addr1, const ReceiverAddress& addr2) const

  {

    if (addr1.group < addr2.group)

    {

      return true;

    }

    else

    {

      if (addr1.group == addr2.group)

        return addr1.number < addr2.number;

      else

        return false;

      }

  }

};

int main()

{

  int eventID = 0;

  FO fo;

  auto lambda = [](int eventID) { return 0; };

  AddressDistributor, int(int)> distributor;  // (3)

  distributor.addReceiver({ 1,1 }, fo);               // (4)

  distributor.addReceiver({ 2,2 }, ExternalHandler);  // (5)

  distributor.addReceiver({ 3,3 }, lambda);           // (6)

  distributor({ 1,1 }, eventID);  // (7)

  distributor({ 2,2 }, eventID);  // (8)

  distributor({ 3,3 }, eventID);  // (9)

}

В строке 1 объявлена структура для адреса, которая состоит из двух полей: идентификатор группы и номер получателя в группе. Сравнить эти две структуры напрямую нельзя, поэтому потребуется реализовать предикат.

В строке 2 объявлен функциональный объект, реализующий предикат для сравнения адресов. Почему именно в таком виде? Дело в том, что std::map требует, чтобы в качестве предиката использовался именно функциональный объект, мы не можем для этого использовать внешнюю функцию или лямбда-выражение. Это связано с тем, что в контейнере предикат хранится в виде переменной с конструктором, тип переменной определяется параметром шаблона. А наличие конструктора может обеспечить только функциональный объект.

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

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