如何用可变参数模板实现无需重复typedef的TypeList?
用可变参数模板实现TypeList并适配散列层次结构
问题描述
我想通过可变参数模板实现TypeList,不用为每种长度的TypeList单独写typedef。现在写了一段无法编译的代码,大致能体现需求,想问这个方案是否可行,或者有没有更优的实现方式?
原错误代码:
#include <tuple> struct NullType { }; template<typename... Ts> struct TypeListParamPackExpander { using U = TypeList<std::tuple_element_t<0, std::tuple<Ts...>>, ...>; }; template <typename T, typename... Ts> struct TypeList { using Head = T; using Tail = TypeListParamPackExpander<Ts...>; }; template <typename T> struct TypeList<T, void> { using Head = T; using Tail = NullType; };
补充说明:这个TypeList是用来实现**散列层次结构(Scatter Hierarchy)**的,我正在读Andrei Alexandrescu的相关书籍,预期使用方式如下:
template <template <typename M> typename B, class TList> class ScatterHierarchy; template <template <typename M> typename B, class T1, class... Ts> class ScatterHierarchy<B, TypeList<T1, Ts...>> : public ScatterHierarchy<B, T1> , public ScatterHierarchy<B, TypeListParamPackExpander<Ts...>> { public: using TList = TypeList<T1, Ts...>; using LeftBase = ScatterHierarchy<B, T1>; using RightBase = ScatterHierarchy<B, TypeListParamPackExpander<Ts...>>; }; template <template <typename> typename B, typename AtomicType> class ScatterHierarchy: public B<AtomicType> { using LeftBase = B<AtomicType>; }; template <template <typename M> typename B> class ScatterHierarchy<B, NullType> { }; struct Message1 { uint32_t x = 5; }; struct Message2 { float f = 0.123; }; struct Message3 { std::string s = "hello!"; }; template <typename Msg> struct Holder { Msg message_; }; int main(void) { using MyScatterHierarchy = ScatterHierarchy<Holder, TypeList<Message1, Message2, Message3>>; MyScatterHierarchy a; std::cout << static_cast<Holder<Message1>>(a).message_.x << std::endl; std::cout << static_cast<Holder<Message2>>(a).message_.f << std::endl; std::cout << static_cast<Holder<Message3>>(a).message_.s << std::endl; };
问题分析
你的代码有几个核心问题导致编译失败:
TypeListParamPackExpander中的参数包写法完全不符合C++语法,且用tuple做中间转换完全多余TypeList的Tail成员是TypeListParamPackExpander<Ts...>类型,而非TypeList类型,后续散列层次结构的递归无法正确匹配模板- 用
void作为终止条件的特化设计不合理,应该直接用空参数包的特化表示空TypeList
最优实现方案
直接用可变参数模板递归实现TypeList,不需要额外的扩展器结构,代码更简洁且符合C++模板规则:
1. 正确的TypeList实现
#include <iostream> #include <string> #include <cstdint> // 空TypeList的终止标记 struct EmptyTypeList {}; // 可变参数版TypeList模板声明 template <typename... Ts> struct TypeList; // 非空TypeList的主模板:第一个元素为Head,剩余元素组成Tail template <typename T, typename... Ts> struct TypeList<T, Ts...> { using Head = T; using Tail = TypeList<Ts...>; }; // 空TypeList的特化:终止递归 template <> struct TypeList<> { using Tail = EmptyTypeList; };
2. 适配Scatter Hierarchy的修改
调整散列层次结构的模板特化,直接依赖TypeList的递归结构:
template <template <typename M> typename B, class TList> class ScatterHierarchy; // 递归处理非空TypeList:继承单个元素的层次结构 + 剩余元素的层次结构 template <template <typename M> typename B, typename T, typename... Ts> class ScatterHierarchy<B, TypeList<T, Ts...>> : public ScatterHierarchy<B, T> , public ScatterHierarchy<B, TypeList<Ts...>> { public: using TList = TypeList<T, Ts...>; using LeftBase = ScatterHierarchy<B, T>; using RightBase = ScatterHierarchy<B, TypeList<Ts...>>; }; // 处理单个原子类型:直接继承B<AtomicType> template <template <typename> typename B, typename AtomicType> class ScatterHierarchy<B, AtomicType> : public B<AtomicType> { using LeftBase = B<AtomicType>; }; // 处理空TypeList:空基类 template <template <typename M> typename B> class ScatterHierarchy<B, EmptyTypeList> {};
3. 完整可编译代码
#include <iostream> #include <string> #include <cstdint> // 空TypeList终止标记 struct EmptyTypeList {}; // 可变参数TypeList实现 template <typename... Ts> struct TypeList; template <typename T, typename... Ts> struct TypeList<T, Ts...> { using Head = T; using Tail = TypeList<Ts...>; }; template <> struct TypeList<> { using Tail = EmptyTypeList; }; // 散列层次结构实现 template <template <typename M> typename B, class TList> class ScatterHierarchy; template <template <typename M> typename B, typename T, typename... Ts> class ScatterHierarchy<B, TypeList<T, Ts...>> : public ScatterHierarchy<B, T> , public ScatterHierarchy<B, TypeList<Ts...>> { public: using TList = TypeList<T, Ts...>; using LeftBase = ScatterHierarchy<B, T>; using RightBase = ScatterHierarchy<B, TypeList<Ts...>>; }; template <template <typename> typename B, typename AtomicType> class ScatterHierarchy<B, AtomicType> : public B<AtomicType> { using LeftBase = B<AtomicType>; }; template <template <typename M> typename B> class ScatterHierarchy<B, EmptyTypeList> {}; // 测试用消息结构体 struct Message1 { uint32_t x = 5; }; struct Message2 { float f = 0.123f; }; struct Message3 { std::string s = "hello!"; }; // Holder模板:存储单个消息类型 template <typename Msg> struct Holder { Msg message_; }; int main() { using MyScatterHierarchy = ScatterHierarchy<Holder, TypeList<Message1, Message2, Message3>>; MyScatterHierarchy a; // 通过static_cast访问对应Holder的成员(用引用避免拷贝) std::cout << static_cast<Holder<Message1>&>(a).message_.x << std::endl; std::cout << static_cast<Holder<Message2>&>(a).message_.f << std::endl; std::cout << static_cast<Holder<Message3>&>(a).message_.s << std::endl; return 0; }
关键改进点
- 直接用可变参数模板递归构建TypeList,无需额外扩展器,逻辑更清晰
- 用空参数包特化作为TypeList的终止条件,符合模板递归的常规写法
- 散列层次结构直接依赖TypeList的Tail成员,递归匹配更准确
- 修正了main函数中static_cast的问题,改用引用避免不必要的对象拷贝
内容的提问来源于stack exchange,提问作者Arthur M
相关产品推荐
相关产品推荐

