Мета-программирование шаблонов: неверное количество аргументов шаблона в Paramater Pack - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь реализовать список, используя Шаблон метапрограммирования , но безуспешно компилирую следующий код:

#include <iostream>

template<int Value>
struct Int {
    static constexpr int value = Value;
};

template<typename H, typename ...TT>
struct List {
    typedef H head;
    typedef List<TT...> next; // <-- Too few template arguments for class template 'List'
    constexpr static int size = sizeof...(TT) + 1;
};

int main() {
    typedef List<Int<1>, Int<2>, Int<3>> list1;
    static_assert(list1::head::value == 1, "Failed"); // = Int<1>
    static_assert(list1::size == 3, "Failed"); // = 3

    typedef typename list1::next list1Tail; // = List<Int<2>, Int<3>>
    static_assert(list1Tail::head::value == 2, "Failed");
    static_assert(list1Tail::size == 2, "Failed"); // = 2

    typedef typename list1Tail::next list2Tail; // = List<Int<3>> <<---error: wrong number of template arguments (0, should be at least 1)
    static_assert(list2Tail::head::value == 3, "Failed");
    static_assert(list2Tail::size == 1, "Failed");

    std::cout << "Passed" << std::endl;
}

С ошибкой:

In instantiation of ‘struct List<Int<3> >’: error: wrong number of template arguments (0, should be at least 1)

Я понимаю, что в моем случае List должен обрабатывать два типа H и ...TT, но:

  1. Почему звонить по номеру List<TT...> недостаточно?
  2. Как мне это исправить?
  3. Каков наилучший подход в этом случае для компиляции кода?

Ответы [ 4 ]

0 голосов
/ 14 января 2019

Вариант решения Холта: вместо второй специализации основным шаблоном рекурсии может быть основной шаблон

template <typename...>
struct List
 { constexpr static int size = 0; };

template<typename H, typename ...TT>
struct List<H, TT...> {
    using head = H;
    using next = typedef List<TT...>; 
    constexpr static int size = sizeof...(TT) + 1;
};

К сожалению, он менее читабелен.

0 голосов
/ 14 января 2019

Укажите специализацию для одного элемента, чтобы не пытаться создавать экземпляр List с пустым пакетом.

template <class H>
struct List<H>
{
    typedef H head;
    constexpr static int size = 1;
};
0 голосов
/ 14 января 2019

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

template <typename...>
struct List;

template <typename H, typename... TT>
struct List<H, TT...> {
    using head = H;
    using next = List<TT... >;
    constexpr static int size = sizeof... (TT) + 1;
};

template <>
struct List<> {
    constexpr static int size = 0;
};

Таким образом, вы можете иметь пустой список List<>, которого вы не можете иметь с текущей версией.

0 голосов
/ 14 января 2019

На последнем шаге List<TT...> будет создана специализация List<>, которая не определена в вашем коде. Вам также следует написать «завершающую» специализацию:

template<typename H>
struct List<H> {
    typedef H head;
    typedef void next;
    constexpr static int size = 1;
};

онлайн-компилятор

...