void NativeHandler(int eventID)  // (1)

{

  //here eventID is 10

}

void AnotherHandler(int contextID, int eventID)  // (2)

{

  //here eventID is 1, contextID is 10;

}

int main()

{

  int eventID = 1; int contextID = 10;

  std::function fnt;  // (3)

  fnt = NativeHandler;           // (4)

  fnt(eventID);                  // (5) NativeHandler will be called

  fnt = std::bind(AnotherHandler, contextID, std::placeholders::_1);  // (6)

  fnt(eventID);  // (7) AnotherHandler will be called

}

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

В строке 6 вызывается функция bind, которая из переданных аргументов формирует объект связывания. На вход std::bind передается имя новой функции-обработчика и аргументы, которые будут передаваться в эту функцию. Первому аргументу здесь будет назначено значение contextID, а второму аргументу будет назначено значение 1-го по порядку аргумента из исходной функции. Здесь конструкция std::placeholders определяет номер аргумента в исходной функции, который будет подставлен в качестве аргумента в перенаправляемую функцию.

Сформированный объект связывания сохраняется в универсальном аргументе. Если мы теперь выполним вызов (строка 7), то будет вызвана функция, назначенная этому объекту, и этой функции будут переданы соответствующие аргументы.

Аналогичным образом может быть объявлено перенаправление вызовов для методов-членов класса, но здесь должно соблюдаться следующее правило: первому аргументу новой функции должен быть назначен первый аргумент исходной функции, потому что он определяет экземпляр класса, для которого вызывается метод. Пример приведен в Листинг 61.

Листинг 61. Перенаправление вызовов для методов-членов класса

#include 

class CallbackHandler

{

public:

  void NativeHandler(int eventID)

  {

    //eventID = 1;

  }

  void AnotherHandler(int contextID, int eventID)

  {

    //eventID = 1, contextID = 10;

  }

};

int main()

{

  using namespace std::placeholders; // (1)

  int eventID = 1; int contextID = 10;

  CallbackHandler handler;

  std::function fnt;

  fnt = &CallbackHandler::NativeHandler;

  fnt(&handler, eventID); // NativeHandler will be called

  fnt = std::bind(&CallbackHandler::AnotherHandler, _1, contextID, _2); // (2)

  fnt(&handler, eventID); // AnotherHandler will be called

}

Здесь в строке 1 мы использовали using namespace, что сокращает объявление позиций аргументов: как видно из строки 2, мы сразу пишем позицию без использования std::placeholders, что значительно компактнее и проще для восприятия. Здесь в исходной функции присутствует неявный параметр с номером 1, который определяет экземпляр класса. Этот параметр назначается первому (неявному) параметру новой функции, а второй параметр исходной функции eventID назначается последнему параметру новой функции.

В общем случае могут быть 4 варианта перенаправления вызовов:

• из функции в функцию (пример в Листинг 60);

• из функции в метод класса;

• из метода класса в другой метод этого же класса (пример в Листинг 61);

• из метода класса в метод другого класса;

• из метода класса в функцию.

Реализация указанных вариантов, по сути, одинакова, отличаются только объявления связывания. Сведем эти объявления в таблицу (Табл. 13).

Табл. 13. Связывания для различных вариантов перенаправления вызовов.

Теперь перенаправление вызовов в исполнителе не представляет сложности: при настройке вместо объекта вызова нужно всего лишь подставить необходимое связывание. Пример для варианта «функция – функция» приведен в Листинг 62, здесь используется инициатор из Листинг 53.

Листинг 62. Перенаправление вызовов в исполнителе

void NativeHandler(int eventID)

{

  //here eventID is 10

}

void AnotherHandler(int contextID, int eventID)

{

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

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