代码之家  ›  专栏  ›  技术社区  ›  Dennis Vash

模板元编程:参数包中的模板参数数目错误

  •  3
  • Dennis Vash  · 技术社区  · 5 年前

    我正在尝试使用 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 回复  |  直到 5 年前
        1
  •  2
  •   user7860670    5 年前

    在最后一步 List<TT...> 将实例化专门化 List<> 您的代码中没有定义。您还应该编写一个“终止”专门化:

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

    online compiler

        2
  •  2
  •   Holt    5 年前

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

    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<> 您当前版本不能使用。

        3
  •  1
  •   Jans    5 年前

    为一个元素提供专门化,这样就不会尝试实例化 List 一包空的。

    template <class H>
    struct List<H>
    {
        typedef H head;
        constexpr static int size = 1;
    };
    
        4
  •  0
  •   max66    5 年前

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

    不幸的是可读性较差。