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



>//General specialization

>template   // (1)

>class function;


>//Partial specialization

>template  // (2)

>class function

>{

>public:


>  Return operator()(ArgumentList… arguments)  // (3)

>  {

>  }

>};


В строке 1 объявлена общая специализация шаблона. Реализация класса здесь отсутствует, поскольку для каждой сигнатуры она будет различной. В строке 2 объявлен шаблон для частичной специализации, в котором два аргумента: тип возвращаемого значения и пакет параметров, передаваемых функции вызова.

В строке 3 объявлен перегруженный оператор, выступающий в качестве функции вызова. Сигнатура оператора содержит тип возвращаемого значения Return и пакет входных параметров arguments, которые разворачиваются в список аргументов. Таким образом, в зависимости от пакета и возвращаемого значения будет сгенерирована соответствующая специализация шаблона.

Описанная реализация всего лишь демонстрирует настройку сигнатуры. Практической пользы от нее немного, потому что тело перегруженного оператора пустое, и вызов осуществлен не будет. Используя описанную технику, добавим настройку сигнатуры к аргументу, реализующему стирание типов (Листинг 48).

Листинг 48. Стирание типов с настройкой сигнатуры

>template 

>class UniArgument;


>template

>class UniArgument  // (1)

>{

>private:

>  struct Callable

>  {

>    virtual Return operator()(ArgumentList… arguments) = 0;  // (3)

>  };


>  std::unique_ptr callablePointer;


>  template 

>  struct CallableObject : Callable

>  {

>    Argument storedArgument;


>    CallableObject(Argument argument) : storedArgument(argument) { }


>    Return operator() (ArgumentList… arguments) override  // (8)

>    {

>      //return storedArgument(arguments…);

>      return std::invoke(storedArgument, arguments…);     // (9)

>    }

>  };


>public:

>  Return operator() (ArgumentList… arguments)        // (10)

>  {

>    return callablePointer->operator()(arguments…);  // (11)

>  }


>  template 

>  void operator = (Argument argument)

>  {

>    callablePointer.reset(new CallableObject(argument));

>  }

>};


По сравнению с реализацией для фиксированной сигнатуры (Листинг 45 п. 4.5.1) изменения здесь следующие. Класс аргумента (строка 1) объявляется в виде шаблона. Параметрами шаблона выступают Return – тип значения, возвращаемого функцией, и ArgumentList