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



>template 

>void Call(CallData& data)  // (1)

>{

>}


>template 

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

>{

>  std::apply(first, data);  // (3)

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

>}


>template 

>void Distribute1(std::tuple data, CallObjects… objects)  // (5)


>{

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

>}


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

Рекурсивная функция объявлена в строке 2. Эта функция извлекает очередной объект из пакета и осуществляет его вызов (строка 3). Здесь используется функция стандартной библиотеки std::apply, которая преобразует содержимое кортежа в список аргументов. Далее, в строке 4, пакет с оставшимися параметрами передается в рекурсивный вызов Call, и процесс повторяется до завершения рекурсии.

5.3.3. Способ 2: объекты в кортеж, данные в пакет

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

Доступ к элементам кортежа осуществляется с помощью вызова

std::get(tuple),

где index – это порядковый номер элемента (начиная с 0), tuple – имя переменной-кортежа. Проблема в том, что индексы должны быть заранее определены как числовые константы, использование переменной для задания индекса не допускается31. Поэтому здесь нельзя использовать ни циклы, ни функции с входным аргументом – индексом.

Можно попробовать объявить шаблон функции, в которой индекс задается параметром шаблона, а внутри функции изменить индекс и осуществить рекурсивный вызов. По идее, в этом случае для каждого индекса должна была бы сгенерироваться отдельная специализированная функция, однако стандарт не допускает специализацию шаблонов функций32. Но специализация шаблонов классов допустима, поэтому выходом будет обернуть функцию в класс – оболочку и уже для класса объявлять специализацию по индексам. Реализация приведена в Листинг 69.

Листинг 69. Распределение при упаковке объектов в кортеж и данных в пакет

>template  // (1)