Обратные вызовы в C++ | страница 53
4.6.4. Исполнитель
Реализация исполнителя для инициатора с универсальным аргументом (см. Листинг 53 п. 4.6.2) приведена в Листинг 56, здесь используется CallbackConverter из Листинг 54 п. 4.6.3.
>class Executor
>{
>public:
> static void staticCallbackHandler(Executor* executor, int eventID) {}
> void callbackHandler(int eventID) {}
> void operator() (int eventID) {}
>};
>void ExternalHandler(void* somePointer, int eventID) {}
>int main()
>{
> int capturedValue = 0;
> Initiator initiator;
> Executor executor;
> // Pointer to the external function
> initiator.setup(CallbackConverter
> // Pointer to the static method
> initiator.setup(CallbackConverter
> // Pointer to the class member method
> initiator.setup(CallbackConverter
> // Functional object
> initiator.setup(executor);
> // Lambda-expression
> initiator.setup([capturedValue](int eventID) {});
>}
Если сравнить приведенную реализацию исполнителя для шаблона-инициатора с фиксированным типом аргумента (Листинг 43 и Листинг 44 п. 4.4.3) с приведенной, то можно заметить следующее. В первом случае для каждого типа аргумента приходится объявлять отдельный инициатор, инстанциируя его соответствующим типом. Здесь инициатор объявляется один раз, после чего тип аргумента вызова настраивается в процессе выполнения программы. В результате упрощается разработка, улучшается гибкость и прозрачность кода.
4.6.5. Инициатор для методов класса
До сих пор для вызова методов класса мы использовали преобразование вызовов. Однако, поскольку std::function непосредственно поддерживает вызов методов, появляется возможность реализовать специализированный инициатор для указанного случая. За основу возьмем инициатор из п. 4.6.2 и модифицируем его.
Как мы видели в реализации универсального аргумента (п. 4.5.3), для вызова метода класса первым параметром должен передаваться указатель на экземпляр класса. Поэтому, в инициатор необходимо добавить переменную для хранения этого указателя. Но поскольку тип класса заранее неизвестен, его следует задавать как параметр, т. е. инициатор должен быть объявлен в виде шаблона. Далее необходимо добавить метод для настройки указателя и, соответственно, при задании сигнатуры и выполнении вызова передавать дополнительный аргумент – указатель на экземпляр класса. Реализация приведена в Листинг 57.