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

std::get(tuple),

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

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

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

template  // (1)

struct TupleIterator

{

  static void IterateTupleItem(CallObjects& callObjects, CallData…callData)  // (2)

  {

    const std::size_t idx = std::tuple_size_v – Index;  // (3)

    std::get(callObjects)(callData…);                         // (4)

    TupleIterator::IterateTupleItem(callObjects, callData…);  // (5)

  }

};

template  // (6)

struct TupleIterator<0, CallObjects, CallData…>     // (7)

{

  static void IterateTupleItem(CallObjects& callObjects, CallData… callData)  // (8)

  {

  }

};

template                         // (9)

void Distribute2(std::tuple callObjects, CallData… callData)  // (10)

{

  TupleIterator  // (11)

  <

  sizeof…(CallObjects),      // (12)

  std::tuple,  // (13)

  CallData…                  // (14)

>

::IterateTupleItem(callObjects, callData…);  // (15)

}

В строке 1 объявляется шаблон структуры. Параметрами шаблона выступают индекс элемента кортежа, сам кортеж и пакет параметров, который определяет данные, передаваемые в вызываемый объект.

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

В строке 3 осуществляется пересчет индекса: от размера (количества элементов) кортежа отнимается текущий индекс. Это необходимо для того, чтобы обход кортежа осуществлялся в прямом порядке, от первого элемента к последнему. Если не выполнять пересчет индексов, то обход будет происходить в обратном порядке.

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

В строке 5 происходит рекурсивный вызов. Объявляется структура с новым значением параметра-индекса, уменьшенным на единицу. Вызывается соответствующая функция с передачей кортежа объектов и пакета параметров, и процесс повторяется заново.

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

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

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

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