В строке 1 объявлен шаблон с двумя параметрами – тип указателя на функцию и тип для контекста. В строке 2 объявлено имя класса. В строке 3 объявлен конструктор, который будет сохранять требуемые значения – указатель на функцию и указатель на контекст, переменные для хранения объявлены в строках 6 и 7. В строке 4 осуществляется перегрузка оператора вызова функции, который делает обратный вызов, передавая информацию и сохраненный контекст.

Рассмотренный шаблон также будет работать для указателей на статический метод класса, только необходимо объявить соответствующие типы указателей.

Для указателей на метод-член класса сделаем специализацию шаблона, как это показано в Листинг 28.

Листинг 28. Функциональный объект для вызова метода класса

template  // (1)

class CallbackConverter   // (2)

{

public:

  using ClassMethod = void(ClassName::*)(int);  // (3)

  CallbackConverter(ClassMethod methodPointer = nullptr, ClassName* classPointer = nullptr)  // (4)

  {

    ptrClass = classPointer; ptrMethod = methodPointer;

  }

  void operator()(int eventID)       // (5)

  {

    ptrClass->*ptrMethod)(eventID);  // (6)

  }

private:

  ClassName* ptrClass;    // (7)

  ClassMethod ptrMethod;  // (8)

};

В строке 1 объявлен шаблон с параметром – именем класса. В строке 2 объявлена специализация шаблона из Листинг 27. Именно эта специализация будет выбрана компилятором, если шаблон инстанциируется указателем на метод класса и указателем на класс. В строке 3 объявлен тип – указатель на метод класса. Этот тип выводится из имени класса, поэтому в шаблоне одного параметра – имени класса – будет достаточно. В строке 4 объявляется конструктор, который будет сохранять требуемые значения – указатель на экземпляр класса и указатель на метод, переменные для хранения объявлены в строках 7 и 8. В строке 5 перегружается оператор вызова функции, который вызывает метод класса.

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

Итак, определив объекты для преобразования вызовов, мы теперь можем использовать в шаблоне-инициаторе, определенном в Листинг 25 п. 4.2.1, любые типы аргументов обратного вызова. Пример приведен в Листинг 29.

Листинг 29. Исполнитель для шаблона-инициатора синхронного вызова

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)

{

  Executor* ptrClass = (Executor*)somePointer;

}

int main()

{

  Executor executor;

  int capturedValue = 0;

  // (2) External function

  using FunctionPointer = void(*)(int, void*);

  using FunctionConverter = CallbackConverter;

  run(FunctionConverter(ExternalHandler, &executor));

  // (3) Static method

  using StaticPointer = void(*)(int, Executor*);

  using StaticConverter = CallbackConverter;

  run(StaticConverter(Executor::staticCallbackHandler, &executor));

  // (4) Member merthod

  using MethodPointer = void(Executor::*)(int);

  using MethodConverter = CallbackConverter;

  run(MethodConverter(&Executor::callbackHandler, &executor));

  // (5) Functional object

  run(executor);

  // (6) lambda-expression

  auto lambda = [capturedValue](int eventID) {/*it will be called by initiator*/};

  run(lambda);

}

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

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