Обратные вызовы в C++ | страница 38
4.4. Асинхронные вызовы
4.4.1. Инициатор
Также, как мы делали при анализе синхронных вызовов, проанализируем различные реализации инициатора асинхронных вызовов (Листинг 36, некоторые фрагменты кода пропущены, чтобы не загромождать описание).
>class Executor;
>class CallbackHandler
>{
>public:
> void operator() (int eventID);
>};
>//Pointer to function
>class Initiator1
>{
>public:
> using ptr_callback = void(*) (int, void*);
> void setup(ptr_callback pPtrCallback, void* pContextData) ;
>private:
> ptr_callback ptrCallback = nullptr;
> void* contextData = nullptr;
>};
>//Pointer to the class static method
>class Initiator2
>{
>public:
> using ptr_callback_static = void(*) (int, Executor*);
> void setup(ptr_callback_static pPtrCallback, Executor* pContextData) ;
>private:
> ptr_callback_static ptrCallback = nullptr;
> Executor* contextData = nullptr;
>};
>//Pointer to the class member method
>class Initiator3
>{
>public:
> using ptr_callback_method = void(Executor::*)(int);
> void setup(Executor* argCallbackClass, ptr_ callback_method argCallbackMethod);
>private:
> Executor* ptrCallbackClass = nullptr;
> ptr_ callback_method ptrCallbackMethod = nullptr;
>};
>//Functional object
>class Initiator4
>{
>public:
> void setup(const CallbackHandler& callback);
>private:
> CallbackHandler callbackObject;
>};
Аналогично синхронным вызовам, можно заметить, что все реализации по своей сути практически одинаковы, отличается только тип и количество аргументов. Попробуем для класса сделать шаблон (Листинг 37).
>template
>class Initiator
>{
>public:
> void setup(const CallbackArgument& argument)
> {
> callbackHandler = argument;
> }
> void run()
> {
> int eventID = 0;
> //Some actions
> callbackHandler(eventID);
> }
>private:
> CallbackArgument callbackHandler;
>};
Получившийся шаблон подходит для реализации с использованием функционального объекта. Для реализаций с использованием указателей на функцию, указателей на статический метод и на метод-член класса можно использовать шаблон для преобразования вызовов (см. п. 4.2.2). А вот реализация с помощью лямбда-выражений здесь работать не будет, потому что хранить лямбда-выражение как аргумент, подобно обычной переменной, нельзя. Рассмотрим этот вопрос подробнее.