2015-05-27 4 views
0

Мне было интересно, можно ли захватить чередующийся шаблон параметров, используя пакет параметров. Например,Пакеты параметров шаблона Variadic с чередующимися типами

template<typename T, size_t U, typename... Args> 
class foo<T, U, Args...> 
{ 
    public: 
    foo() : my_T(nullptr), my_U(U) {} 

    private: 
    T* my_T; 
    size_t my_U; 
    foo<Args...> my_next_foo; 
} 

Так что это не сработает, поскольку Args - это пакет параметров только типов. Есть ли способ изменить это, чтобы шаблон типа T, size_t U мог быть правильно захвачен в вариационном шаблоне? Благодаря

+1

Да.Возьмите пары типа и значения как список типов. – Columbo

+0

и вообще (когда ваш шаблон не повторяется), общий способ передачи аргументов, отличных от типа, заключается в помещении их внутри класса. Примеры включают 'std :: true_type',' std :: integ_constant' и т. Д. – davidhigh

ответ

3

Ценности в качестве параметров шаблона являются гражданами второго сорта, по моему опыту.

Обновление им первого класса с псевдонимом:

template<std::size_t n> 
using size = std::integral_constant<std::size_t, n>; 

затем шаблон матча:

template<class...> 
struct foo; 
template<> 
struct foo<> { 
    // empty 
}; 
template<class T, size_t U, typename... Args> 
struct foo<T, size<U>, Args...> { 
    foo() : my_T(nullptr), my_U(U) {} 

private: 
    T* my_T; 
    size_t my_U; 
    foo<Args...> my_next_foo; 
}; 

и боб ваш дядя.

Обратите внимание, однако, что принятие U в качестве параметра шаблона, а затем сохранение его как значения времени выполнения, является весьма сомнительным.

Пользователи foo должны сделать:

foo< Chicken, size<3>, Dog, size<17> > 

вместо

foo< Chicken, 3, Dog, 17 > 
+0

Кажется, это лучший вариант. Один вопрос, какова была бы ошибка хранения параметра шаблона для использования во время выполнения? – armstrhu

+0

@armstrhu вы можете получить к ним доступ во время выполнения, не сохраняя их. 'enum {my_U = U};' позволяет вам легко получить доступ к значению времени компиляции 'U' из типа' foo '. Причина, по которой это плохой знак, заключается в том, что если у вас есть значение, которое меняется во время выполнения, почему бы не передать его как значение времени выполнения, а не кодировать его в типе? – Yakk

+0

ahh, да, хороший момент. Итак, вы правы, для моего приложения мне действительно не нужно сохранять значение U, просто получить к нему доступ. Думаю, в моем маленьком примере выше я не совсем так думал. В принципе, я создаю вариационный шаблон по набору std :: array, и я пытался выяснить, как можно передать тип и длину массива. Так что действительно, мой T * на самом деле является std :: array * и не будет переменной size_t U. Ваше решение должно решить мою проблему независимо. благодаря – armstrhu

2

Конечно, просто написать собственную пару:

template <typename T, size_t U> 
struct foo_pair { }; 

И есть пакет тех:

template<typename T, size_t U, typename... Pairs> 
class foo<foo_pair<T, U>, Pairs...> { 
    ... 
}; 

Какой должен быть создан как:

foo<foo_pair<int, 4>, foo_pair<char, 17>, ...> f; 
0

Вы можете пройти Args до foo как std::tuple. Используйте std::integral_constant для U вместо передачи интегральной константы в качестве параметра шаблона в std::tuple. Затем пакет параметров Args содержит все пары типов и размеров.

Например, при создании экземпляра Foo вы могли бы сделать это с типом, как это:

Foo<std::tuple<int, std::integral_constant<size_t, 5> >, 
    std::tuple<char, std::integral_constant<size_t, 3> > > 

При реализации foo, вы должны передать свой параметр обновления к другому std::tuple и использовать std::tuple_element, чтобы выбрать Nth элемент из кортеж.

Это всего лишь один из возможных подходов, вам может быть проще реализовать foo, если вы используете списки типов.

+0

Проблема с 'tuple' таким образом заключается в том, что это большой сложный класс, чтобы экземпляры были оптимальными во время выполнения. Использование этого как не более чем способ собрать вместе типы может заставить компилятор получить скрипучие, бесполезно. – Yakk

0

Вы можете создать класс, представляющий контейнер T* my_T данных с size_t my_U. Имея это, вы можете реализовать свой шаблон:

#include <array> 

using std::size_t; 

template<typename... Args> 
struct foo; 

template<typename T, size_t N> 
struct foo<std::array<T, N>> 
{ 
    std::array<T, N> array; 
}; 

template<typename T, size_t N, typename... Args> 
struct foo<std::array<T, N>, Args...> 
{ 
    std::array<T, N> array; 
    foo<Args...> next_array; 
}; 

int main() { 
    foo<std::array<char, 1>, std::array<short, 2>, std::array<int, 4>> foos; 
} 

Примечание: Я использую std :: array в качестве замены контейнера данных.