<p>4.1. Общие понятия шаблонов</p>

Шаблоны в C++ являются инструментом, реализующим параметрический полиморфизм, что означает возможность построения единого (обобщенного) кода для различных типов данных16. В таком коде не задаются конкретные типы, а вводятся параметры, в которые затем подставляется нужный тип данных. Чтобы код работал корректно, типы должны удовлетворять некоторым соглашениям, или, другими словами, поддерживать определенный интерфейс.

Обобщенный код – это код, реализующий заданную функциональность без привязки к типам данных.

Шаблоны объявляются ключевым словом template, после которого в угловых скобках перечисляются параметры. Параметрами шаблона могут быть как типы данных, так и значения.

Пример объявления шаблона:

template SomeTemplate

Здесь объявлен шаблон с одним параметром-типом type и параметром-значением value.

Параметрам шаблона, как типам, так и значениям, могут быть назначены значения по умолчанию:

template SomeTemplate

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

Инстанциирование шаблона – это объявление экземпляра шаблона с заданными типами.

Инстанциирование шаблона может быть явным и неявным. При явном инстанциировании типы параметров шаблона объявляются, а при неявном – выводятся, исходя из типов входных аргументов. Пример объявления шаблонов и их инстанциирование представлены в Листинг 23.

Листинг 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++ порождает немало проблем.

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

<p>4.2. Синхронные вызовы</p><p>4.2.1. Инициатор</p>

Проанализируем различные реализации инициатора синхронных вызовов (Листинг 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*);

using ptr_callback_method = void(Executor::*)(int);

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

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