You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用可变参数模板实现无需重复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 03:47:19