Обратные вызовы в C++ | страница 81
>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 требует, чтобы в качестве предиката использовался именно функциональный объект, мы не можем для этого использовать внешнюю функцию или лямбда-выражение. Это связано с тем, что в контейнере предикат хранится в виде переменной с конструктором, тип переменной определяется параметром шаблона. А наличие конструктора может обеспечить только функциональный объект.
Указанный подход имеет как достоинства, так и недостатки. С одной стороны, нам достаточно всего лишь объявить тип объекта в параметре шаблона, а затем про него можно забыть. Объект не нужно ни настраивать, ни передавать в конструктор как входной аргумент. С другой стороны, было бы удобно использовать в качестве предиката что-либо другое, например, лямбда-выражение или внешнюю функцию. Но в этом случае предикат пришлось бы инициализировать в конструкторе, причем ему нельзя было бы назначить значение по умолчанию. В любом случае, мы вынуждены следовать заданной реализации, поэтому предикат объявляем как функциональный объект.