Добавим в реализацию инициатора, описанного в Листинг 37 п. 4.4.1, два конструктора. Один конструктор будет с переменной – аргументом обратного вызова для инициализации члена класса. Другой конструктор будет без аргументов (конструктор по умолчанию), чтобы оставить возможность отложенной настройки (Листинг 41).

Листинг 41. Инициатор с дополнительными конструкторами

template

class Initiator

{

public:

  Initiator() {}

  Initiator(const CallbackArgument& argument) : callbackHandler(argument) {}

  void setup(const CallbackArgument& argument)

  {

    callbackHandler = argument;

  }

  void run()

  {

    int eventID = 0;

    //Some actions

    callbackHandler(eventID);

  }

private:

  CallbackArgument callbackHandler;

};

Для любых типов аргументов обратного вызова, кроме лямбда-выражений, допускается использование обоих конструкторов. Для лямбда-выражений допускается использование только конструктора с аргументом, при попытке использования конструктора по умолчанию компилятор выдаст ошибку. Кроме того, в этом случае нельзя будет вызвать метод setup – также будет сгенерирована ошибка. Таким образом, использование инициатора с лямбда-выражением не предполагает динамической модификации: настройка происходит один раз в конструкторе при инстанциировании шаблона, и больше изменить ее нельзя20.

А какой тип аргумента нам указывать при инстанциировании шаблона, ведь тип лямбда-выражения является анонимным? Для этой цели мы будем использовать ключевое слово decltype, которое возвращает тип объявленной переменной (см. Листинг 42).

Листинг 42.Инстанциирование шаблона асинхронного обратного вызова для лямбда-выражения

int capture = 10;

auto lambda = [capture](int eventID) {/*this is a body of lambda*/};

Initiator callbackLambda1 (lambda); // Ok, initialization in constructor

Initiator callbackLambda = lambda; // Ok, implicit constructor call

Initiator callbackLambda2;  //Error: attempting to reference a deleted function

callbackLambda.setup(lambda);  //Error:  ‘operator’ =  attempting to reference a deleted function

callbackLambda.run();

<p>4.4.3. Исполнитель</p>

В Листинг 43 приведены примеры реализации исполнителя для различных типов аргументов. Объявления класса CallbackConverter представлены в Листинг 27 и Листинг 28 п. 4.2.2, инициатор используется из Листинг 41 п. 4.4.2.

Листинг 43. Исполнитель для шаблона-инициатора с различными типами аргумента

class Executor  // (1)

{

public:

  static void staticCallbackHandler(int eventID, Executor* executor) {}

  void callbackHandler(int eventID) {}

  void operator() (int eventID) {}

};

void ExternalHandler(int eventID, void* somePointer) {}  // (2)

int main()

{

  Executor executor;  // (3)

  int capturedValue = 0;

  // (4)  Pointer to the external function

  using PtrExtFunc = void(*) (int, void*);                                 // (5)

  using CallbackExtFunction = CallbackConverter;        // (6)

  Initiator initExtFunction;                          // (7)

  initExtFunction.setup(CallbackExtFunction(ExternalHandler, &executor));  // (8)

  // (9) Pointer to the static method

  using PtrStaticMethod = void(*) (int, Executor*);  // (10)

  using CallbacStaticMethod = CallbackConverter;                // (11)

  Initiator initStaticMethod;                                          // (12)

Перейти на страницу:

Похожие книги