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) с приведенной, то можно заметить следующее. В первом случае для каждого типа аргумента приходится объявлять отдельный инициатор, инстанциируя его соответствующим типом. Здесь инициатор объявляется один раз, после чего тип аргумента вызова настраивается в процессе выполнения программы. В результате упрощается разработка, улучшается гибкость и прозрачность кода.

<p>4.6.5. Инициатор для методов класса</p>

До сих пор для вызова методов класса мы использовали преобразование вызовов. Однако, поскольку std::function непосредственно поддерживает вызов методов, появляется возможность реализовать специализированный инициатор для указанного случая. За основу возьмем инициатор из п. 4.6.2 и модифицируем его.

Как мы видели в реализации универсального аргумента (п. 4.5.3), для вызова метода класса первым параметром должен передаваться указатель на экземпляр класса. Поэтому, в инициатор необходимо добавить переменную для хранения этого указателя. Но поскольку тип класса заранее неизвестен, его следует задавать как параметр, т. е. инициатор должен быть объявлен в виде шаблона. Далее необходимо добавить метод для настройки указателя и, соответственно, при задании сигнатуры и выполнении вызова передавать дополнительный аргумент – указатель на экземпляр класса. Реализация приведена в Листинг 57.

Листинг 57. Инициатор с оболочкой std::function для вызова методов класса

template  // (1)

class InitiatorForClass

{

public:

  template

  void setup(const CallbackArgument argument)  // (2)

  {

    callbackHandler = argument;

  }

  void setupInstance (ClassName* classObject)  // (3)

  {

    ptrClass = classObject;

  }

  void run()  // (4)

  {

      int eventID = 0;

      //Some actions

      callbackHandler(ptrClass, eventID);  // (5)

  }

private:

  std::function callbackHandler;  // (6)

  ClassName* ptrClass = nullptr;                         // (7)

};

В строке 1 объявлен шаблон класса. В строке 2 объявлен метод для настройки аргумента, в качестве которого выступает указатель на метод-член. В строке 3 объявлен метод для настройки экземпляра класса. Метод запуска 4 такой же, как и в исходном, за исключением того, что при вызове в аргумент дополнительно передается указатель на класс (строка 5). В строке 6 инстанциируется аргумент для вызова метода класса, в сигнатуре первым параметром выступает указатель на класс, задаваемый параметром шаблона-инициатора. В строке 7 объявлена переменная для хранения указателя на экземпляр класса.

Итак, модифицировав инициатор из Листинг 53 п. 4.6.2, мы реализовали отдельный инициатор для вызова методов-членов. Используя частичную специализацию шаблона, можно сделать так, чтобы оба инициатора объявлялись одинаковым способом (Листинг 58).

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

template  // (1)

class Initiator

{

  //… Implementation for origin initiator

};

template  // (2)

class Initiator

{

  //… Implementation for class method call initiator

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

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