Обратные вызовы в C++ | страница 53



4.6.4. Исполнитель

Реализация исполнителя для инициатора с универсальным аргументом (см. Листинг 53 п. 4.6.2) приведена в Листинг 56, здесь используется CallbackConverter из Листинг 54 п. 4.6.3.

Листинг 56. Исполнитель для инициатора с оболочкой std::function

>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(ExternalHandler, &executor));


>  // Pointer to the static method

>  initiator.setup(CallbackConverter(Executor::staticCallbackHandler, &executor));


>  // Pointer to the class member method

>  initiator.setup(CallbackConverter(&Executor::callbackHandler, &executor));


>  // 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.