Ответ 1
То, что выглядит get<1>(t)
, будет зависеть от реализации mtuple
. Типичная реализация наследует от типа, который содержит каждый аргумент, поэтому mtuple<A,B,C>
наследует от TupleHead<A>
(который имеет член типа A
), а также наследует от TupleTail<B,C>
. TupleTail<B,C>
наследует от TupleHead<B>
(который имеет член типа B
) и TupleTail<C>
. TupleTail<C>
наследует от TupleHead<C>
(который имеет член типа C
.)
Теперь, если вы также даете каждому базовому классу целочисленный параметр:
mtuple<A,B,C>
наследует от TupleHead<0,A>
и TupleTail<1,B,C>
TupleTail<1,B,C>
наследует от TupleHead<1,B>
и TupleTail<2,C>
TupleTail<2,C>
наследуется от TupleHead<2,C>
Теперь относительно просто написать get<1>
, поскольку mtuple
имеет единственный уникальный базовый класс типа TupleHead<1,B>
, который может быть получен с помощью upcast, а затем возвращает член B
этого базового класса.
[Изменить: get<1>(m)
должен знать тип B
, который соответствует элементу кортежа с индексом 1, поскольку вы используете что-то вроде std::tuple_element
, которое также опирается на иерархию рекурсивного наследования, описанную выше, и использует частичную специализацию для получения базового класса TupleHead<1,T>
с индексом 1, затем определяет параметр T
в той частичной специализации, которая дает в нашем примере B
.]
Многие из методов, используемых с вариационными шаблонами, - это методы функционального программирования, такие как работа с первым элементом пакета параметров шаблона, а затем рекурсивно выполнение того же самого в остальной части пакета, пока вы не обработали все элементы, Существует не так много вещей, которые вы можете сделать с пакетом параметров шаблона напрямую, за исключением подсчета его размера (с помощью sizeof...
) или создания экземпляра другого шаблона с ним, поэтому обычный подход заключается в создании экземпляра другого шаблона, который разделяет пакет Args
на ArgHead, ArgsTail...
и обрабатывает голову, а затем рекурсивно делает то же самое с ArgsTail