【问题标题】:Template meta-programming: Wrong number of template arguments in Paramater Pack模板元编程:参数包中的模板参数数量错误
【发布时间】:2019-06-08 18:38:27
【问题描述】:

我正在尝试使用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&lt;TT...&gt; 还不够?
  2. 我应该如何解决它?
  3. 在这种情况下编译代码的最佳方法是什么?

【问题讨论】:

  • 想想当TT 为空时会发生什么,你有List&lt;TT...&gt; 但你至少需要H 来定义最少。递归结束时需要专门化。

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


【解决方案1】:

在最后一步List&lt;TT...&gt; 将实例化未在您的代码中定义的特化List&lt;&gt;。您还应该编写“终止”专业化:

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

online compiler

【讨论】:

  • @DennisVash 这实际上取决于此模板的用例。我刚刚复制了主模板主体,但总是同时拥有 head 和 next 节点似乎是合理的。
【解决方案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&lt;&gt;,而您的当前版本无法拥有该列表。

【讨论】:

    【解决方案3】:

    为一个元素提供特化,这样您就不会尝试用空包实例化List。

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

    【讨论】:

      【解决方案4】:

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

      不幸的是可读性较差。

      【讨论】:

        猜你喜欢
        • 2017-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-11
        • 2018-12-03
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        相关资源
        最近更新 更多