如何在模板元编程中创建动态列表?

How do I create a dynamic list in template metaprogramming?

我一直在尝试模板元编程,但在制作动态列表时遇到了一些麻烦。我试过了

#include <iostream>
template<int I>
struct Int {

};
template<class _Value, class ..._Others>
struct List {
    typedef _Value Value;
    typedef List<_Others...> Next;
};
template<class _Value>
struct List<_Value, void> {
    typedef _Value Value;
    typedef void Next;
};

template<class _List>
void PrintList() {
    std::cout << typename _List::Value::I << "\n";
    PrintList<typename _List::Next>();
};
template<>
void PrintList<void>() {};

int main() {
    PrintList<List<Int<1>, Int<2>, Int<3>>>();
}

但是我遇到了 2 个我无法弄清楚的编译错误。第一个是 std::cout << typename _List::Value::I << "\n"; 上的 expected '(' before '<<' token。我不知道如何打印出 int 值(我也试过 (typename _List::Value)::I)。

第二个错误是我在 typedef List<_Others...> Next; 处的模板参数数量错误。不应该第一个参数上限为 Value,其余的 Others

您不能使用 :: 语法访问模板参数。通常的约定是为类型添加 type using,为值添加 value constexpr static 成员。

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

然后使用 std::cout << _List::Value::value << "\n";。它不是一个类型,所以把 typename 放在那里也是不正确的。

第二个错误是因为你定义了 List 至少有一个参数,但你递归到 List<_Others...> 最后是空的。即使你想用 void 修复它,你忘记将它添加到列表中,试试 PrintList<List<Int<1>, Int<2>, Int<3>,void>>();

但是没有必要设置标记值,请参阅:

#include <iostream>
template<int I>
struct Int {
    static constexpr auto value=I;
};
//Define List as naturally having any number of arguments, even zero.
template<class...Ts>
struct List{};

//Non-empty specialization.
template<class Head, class...Tail>
struct List<Head,Tail...>{
    using head = Head;
    using tail = List<Tail...>;
};

template<class _List>
void PrintList() {
    std::cout <<  _List::head::value << "\n";
    PrintList<typename _List::tail>();
};
//Printing empty list.
template<>
void PrintList<List<>>() {};

int main() {
    PrintList<List<Int<1>, Int<2>, Int<3>>>();
}

在C++中使用using更好,它们更易读并且可以模板化。

在 C++17 中你可以使用折叠表达式:

template<typename...Elements>
void fold_print(List<Elements...>){
    ((std::cout<<Elements::value<<'\n'),...);
}
int main() {
    fold_print(List<Int<1>, Int<2>, Int<3>>{});
}

但是函数只能解包它们的参数,所以语法略有不同。或者它需要一个更多的 struct 包装器来解压它们。