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

如何使C++预定义类型列表适配可变参数函数调用?

解决折叠表达式无法展开封装类型包的问题

嘿,这个问题我太懂了!你现在的核心困扰在于:my_list并不是你以为的「参数包」,它是一个单独的模板结构体类型——也就是tl<int, float, uint64_t>这个整体。当你把它传给myFunc2时,模板参数Types...就只包含这一个类型,所以折叠表达式自然只会执行一次,打印的是tl结构体本身的大小,而不是里面每个类型的大小。

要让myFunc2<my_list>()这种调用方式生效,我们需要从my_list里提取出它内部封装的参数包,再传递给原函数。下面是两种简单易行的方案:

方案1:用函数重载自动展开(C++17及以上)

我们可以给myFunc2新增一个重载版本,专门接受tl<Types...>类型的实例,然后自动转发到处理参数包的原函数:

#include <iostream>
#include <cstdint>

template <typename ... Types> struct tl { };
using my_list = tl<int, float, uint64_t>;

// 原函数:处理普通类型参数包
template <typename ... Types> void myFunc2() {
    (std::cout << "Size: " << sizeof(Types) << std::endl, ...);
}

// 新增重载:专门处理tl类型,自动提取内部参数包
template <typename ... Types> void myFunc2(tl<Types...>) {
    myFunc2<Types...>();
}

int main () {
    myFunc2<int,uint64_t,bool,uint16_t>(); // 正常打印每个类型大小
    myFunc2(my_list{}); // 现在会展开my_list内部的int、float、uint64_t,打印三次
    return 0;
}

调用时只需要传入一个my_list的临时对象,重载函数会自动推导并展开内部的参数包,完美满足你的需求。

方案2:用类型萃取器提取参数包(更灵活)

如果你希望保持myFunc2<my_list>()这种模板参数调用的写法,可以写一个类型萃取器,把tl内部的参数包提取出来:

#include <iostream>
#include <cstdint>
#include <tuple>

template <typename ... Types> struct tl { };
using my_list = tl<int, float, uint64_t>;

// 类型萃取器:提取tl结构体内部的参数包
template <typename T> struct extract_tl_types;

template <typename ... Types> 
struct extract_tl_types<tl<Types...>> {
    using args_pack = tl<Types...>;
};

// 原函数保持不变
template <typename ... Types> void myFunc2() {
    (std::cout << "Size: " << sizeof(Types) << std::endl, ...);
}

// 辅助函数:利用萃取器展开参数包
template <typename T> void myFunc2() {
    // 用C++17的模板lambda来推导参数包
    []<typename ... Ts>(tl<Ts...>) {
        myFunc2<Ts...>();
    }(typename extract_tl_types<T>::args_pack{});
}

int main () {
    myFunc2<int,uint64_t,bool,uint16_t>(); // 正常工作
    myFunc2<my_list>(); // 现在会展开内部类型,打印三次
    return 0;
}

这个方案更灵活,如果你后续需要对封装的类型包做更多元编程操作,类型萃取器可以复用。

为什么原来的调用不行?

再补充一句:你原来的myFunc2<my_list>()中,模板参数Types...被推导为[tl<int, float, uint64_t>]——也就是一个包含单个类型的参数包,所以折叠表达式只执行一次,打印的是sizeof(tl<int, float, uint64_t>)(通常是空结构体,大小为1或0,取决于编译器),而不是你期望的每个内部类型的大小。

内容的提问来源于stack exchange,提问作者Waldorf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:45:03