Обратные вызовы в C++ | страница 69
>{
> TupleIterator3 // (11)
> <
> sizeof…(CallObjects), // (12)
> std::tuple
> std::tuple
> >
> ::IterateTupleItem(callObjects, callData); // (15)
>}
По сравнению с Листинг 69 п. 5.3.3 изменения здесь следующие. Входными параметрами распределяющей функции (строка 10) являются кортеж объектов и кортеж данных (ранее параметр для данных задавался пакетом). В объявлениях шаблонов структур для обхода кортежа (строки 1, 6) параметр, определяющий данные вызова, объявляется как тип (ранее это был пакет). Вызов объекта (строка 4) осуществляется через std::apply (ранее объект вызывался непосредственно). И еще здесь изменены имена структур, чтобы избежать конфликта имен с предыдущей реализацией.
5.3.5. Сравнение способов
В Листинг 71 приведен пример распределения вызовов с использованием различных способов настройки сигнатуры, в качестве данных выступают два числовых значения.
>void ExternalHandler(int eventID, int contextID) {}
>struct FO
>{
>void callbackHandler(int eventID, int contextID) {}
>void operator() (int eventID, int contextID) {}
>};
>int main()
>{
>int eventID = 0, contextID = 1;
>FO fo;
>auto lambda = [](int eventID, int contextID) {};
>auto cb2cl = std::bind(&FO::callbackHandler, fo, _1, _2);
>Distribute1(std::tuple(eventID, contextID), ExternalHandler, fo, cb2cl, lambda);
>Distribute2(std::tuple(ExternalHandler, fo, cb2cl, lambda), eventID, contextID);
>Distribute3(std::tuple(ExternalHandler, fo, cb2cl, lambda), std::tuple(eventID, contextID));
>}
С точки зрения эффективности все три способа, в общем-то, равноценны. С точки зрения дизайна можно сказать следующее: первый способ самый простой в реализации; второй способ позволяет легко модифицировать код для сбора дополнительной информации при выполнении вызовов; третий способ позволяет передавать дополнительные параметры в функцию распределения, если это необходимо.
5.3.6. Настройка сигнатуры для перенаправления
В рассмотренных выше примерах мы предполагали, что все получатели используют одну и ту же сигнатуру вызова. Но что делать, если они имеют разные сигнатуры? Нам необходимо разработать какой-то объект, который бы обеспечивал следующее: настройку входной сигнатуры, в которую передаются данные вызова; настройку выходной сигнатуры, которая определяется получателем; преобразование одной сигнатуры в другую. По сути дела, необходимо обеспечить перенаправление вызовов, что решается с помощью инструментов STL, а именно – объектов связывания (см. п. 4.6.2). В этом случае в функцию распределителя вместо объекта-получателя передается объект-связывание, который осуществляет перенаправление вызова с заданной сигнатурой. Пример реализации приведен в Листинг 72; здесь в качестве распределяющей функции используется реализация из Листинг 69 п. 5.3.3.