Обработка вариативных шаблонов в С++ 11

Недавно я начал использовать С++ 11, и я прочитал в учебнике о вариативных шаблонах. Я понял, что мы можем определить вариационный шаблон, подобный этому

// example class that uses variadic template
template<typename ...Args> struct mtuple;

Но как я могу обрабатывать аргументы шаблона класса mtuple (т.е. как выглядит get<int>(mtuple_obj)?)?

Ответ 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

Ответ 2

Нет простого механизма для итерации значений вариационного шаблона. Но это можно сделать рекурсивно. Вот пример:

template<typename T, typename... Args>
void print_values(const char *s, T value, Args... args)
{
    while (*s) {
        if (*s == '%' && *(++s) != '%') {
            std::cout << value;
            ++s;
            print_values(s, args...);
            return;
        }
        cout << *(s++);
    }
}

Итак, если я вызываю print_values("%d %d %d", 1, 2, 3), я получаю это дерево рекурсии:

print_values("%d %d %d", 1, 2, 3) // value -> 1, args... -> 2,3
print_values("%d %d", 2, 3) // value -> 2, args... -> 3
print_values("%d", 3) // value -> 3, args... -> NULL
print_values("") // value -> NULL, args... -> NULL

Я рекурсивно вызываю print_values(), даже когда * s == 0 для обнаружения дополнительных аргументов

Источник: http://en.wikipedia.org/wiki/Variadic_templates