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



Листинг 23. Объявление шаблона и его инстанциирование

>template  // (1)

>class StaticArray

>{

>public:

>  type array[size];

>};


>template           // (2)

>TYPE Sum(TYPE s2, TYPE s3)

>{

>  return s2 + s3;

>}


>int main()

>{

>  StaticArray someArray;  // (3)


>  int a = 0; double x = 8;

>  Sum(a, a);                      // (4)

>  Sum (a, x);             // (5)

>}


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


Вообще, шаблоны в C++ – это обширная тема, заслуживающая отдельной книги, поэтому изложить ее полностью не представляется возможным. Для лучшего понимания дальнейшего материала, кроме уже изложенных базовых понятий, рекомендуется ознакомиться со следующими темами: шаблоны с переменным числом параметров; частичная специализация шаблонов; автоматический вывод типов17.

Программирование с использованием шаблонов, или, как его еще называют, метапрограммирование, достаточно сложное, поскольку предполагает высокий уровень абстракции в сочетании с неявным генерированием кода на этапе компиляции. Здесь используется другая парадигма, которая очень отличается от привычного объектно-ориентированного подхода; по своей природе шаблоны ближе к функциональному программированию. Однако именно благодаря указанным особенностям они позволяют легко и естественно решать многие задачи, в которых использование классических средств C++ порождает немало проблем.

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

4.2. Синхронные вызовы

4.2.1. Инициатор

Проанализируем различные реализации инициатора синхронных вызовов (Листинг 24):

Листинг 24. Реализации инициатора для синхронных вызовов

>class Executor

>{

>public:

>  void callbackHandler(int eventID);

>  void operator() (int eventID);

>};


>using ptr_callback = void(*) (int, void*);

>using ptr_callback_static = void(*) (int, Executor*);