В строке 1 объявлена общая специализация шаблона, параметрами выступают адрес получателя Address, предикат для сравнения AddressCompare и сигнатура распределяющей функции Function. Реализация здесь отсутствует, поскольку для каждой сигнатуры требуется отдельная специализация – аналогично настройке сигнатуры для универсального аргумента (п. 4.5.2).
В строке 2 объявлена частичная специализация, в которой дополнительно представлены параметр для возвращаемого значения Return и пакет параметров ArgumentList для аргументов функции. В строке 3 объявлен класс, который специализируется сигнатурой из указанных параметров.
В строке 4 объявлен шаблон метода для добавления получателя, который принимает адрес address, вызываемый объект object и добавляет их в контейнер. В строке 5 объявлен метод для удаления получателя. Оба метода работают с контейнером, который объявлен в строке 10. Контейнер объявлен как std::map, ключом является адрес, а значением – объект std::function с заданной сигнатурой.
В строке 6 объявлен перегруженный оператор, который осуществляет распределение вызовов, т. е. является распределяющей функцией. Он пробегает по всем элементам контейнера и осуществляет вызов в соответствии с списком аргументов, типы которых задаются в пакете параметров шаблона класса. Поскольку мы используем адресное распределение, т. е. предполагается, что вызов попадает только одному получателю, то мы операторе можем вернуть результат вызова.
В строке 7 происходит поиск получателя по адресу. Если получатель найден, то происходит вызов объекта (строка 8). Если получатель не найден, то генерируется исключение (строка 9), иначе какой результат нам возвратить?
5.7.3. Использование адресного распределения
Пример использования адресного распределения приведен в Листинг 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
{
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
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 требует, чтобы в качестве предиката использовался именно функциональный объект, мы не можем для этого использовать внешнюю функцию или лямбда-выражение. Это связано с тем, что в контейнере предикат хранится в виде переменной с конструктором, тип переменной определяется параметром шаблона. А наличие конструктора может обеспечить только функциональный объект.