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



Листинг 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

>};


В строке 1 объявлен исходный класс, но теперь он является шаблоном с пакетом параметров. Пакет параметров здесь не используется, он нужен только для дальнейшей специализации.

В строке 2 объявлен шаблон для вызова методов-членов. Поскольку его имя совпадает с именем предыдущего, компилятор будет считать, что здесь определяется не новый класс, а специализация объявленного ранее. В объявлении указан параметр, предполагается, что в этом качестве будет использоваться имя класса. Теперь, если при инстанциировании шаблона будет задаваться параметр, будет выбрана специализация для вызова методов-членов. При отсутствии параметров будет выбран исходный шаблон.


Использование двух типов инициатора (исходного и специализированного) для вызова методов класса приведено в Листинг 59, здесь используется преобразование вызовов из Листинг 54 п. 4.6.3.