模板元编程:Paramater Pack中的模板参数数量错误

时间:2019-01-14 18:28:45

标签: c++ c++11 variadic-templates template-meta-programming

我正在尝试使用Template meta-programming实现列表,但编译下一个代码失败:

#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 :(得分:2)

在最后一步,List<TT...>将实例化代码中未定义的专业化List<>。您还应该编写“终止”专业化知识:

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

online compiler

答案 1 :(得分:2)

对于空列表或具有单个元素的列表,您需要专门化。一种可能性是,首先声明一个完全可变的模板,然后创建两个专门化名称:

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<>,而您的当前版本是空列表。

答案 2 :(得分:1)

为一个元素提供一种特殊化,因此您不必尝试实例化带有空包的List

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

答案 3 :(得分:0)

Holt解决方案的差异:递归的基本情况可以作为主要模板,而不是第二种专业化方法

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;
};

不幸的是,它的可读性较差。