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



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

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

Реализация описанной техники приведена в Листинг 63.

Листинг 63. Распределяющая функция для статического набора получателей

>void Call()  // (1)

>{

>}


>template < typename First, typename…Others>

>void Call(First& first, Others…rest)  // (2)

>{

>  first();            // (3)

>  Call(rest…);      // (4)

>}


>template 

>void Distribute(CallObjects… objects)  // (5)

>{

>  Call(objects…);  // (6)

>}


Графически развертывание пакета параметров для трех аргументов изображено на Рис. 22. Процесс начинается с вызова распределяющей функции, которая объявлена в строке 5. Здесь используется пакет параметров objects, который содержит объекты вызова. Внутри этой функции, в строке 6, происходит первый вызов рекурсивной функции, которой на вход передаются соответствующий аргумент в виде пакета.

Рекурсивная функция Call объявлена в строке 2. Эта функция принимает два аргумента: первый параметр из пакета first и пакет остальных параметров rest. При первом вызове пакет параметров из Distribute передается в эту функцию, и там происходит его распаковка: первый параметр извлекается и помещается в first, оставшаяся часть пакета записывается в rest. В строке 3 производится вызов, а пакет с оставшимися параметрами передается в рекурсивный вызов Call (строка 4).

Итак, на каждом шаге рекурсивного вызова из пакета извлекается очередной параметр, а размер исходного пакета уменьшается. Таким образом, в итоге все параметры будут извлечены, и пакет станет пустым. Эта ситуация обрабатывается путем объявления функции с пустым пакетом параметров, т. е. функции, которая на вход не принимает ни одного аргумента (строка 1). Тело этой функции пустое, в ней происходит возврат управления, и по цепочке рекурсивных вызовов управление возвращается в исходную точку в строке 6.