可变参数模板是C++11引入的特性,通过参数包(typename.../Args...)和展开操作(...)支持任意数量类型与参数;核心用法包括sizeof...获取数量、递归分解处理单个参数、C++17折叠表达式简化展开,广泛用于tuple、variant等标准库组件。

可变参数模板是C++11引入的重要特性,用于编写能接受任意数量、任意类型参数的模板函数或类。核心在于参数包(parameter pack)和展开操作(...)。
基本语法:声明与展开
用typename...或class...声明类型参数包,用Args...声明形参包。展开时args...会将参数依次代入上下文。
最简示例:打印参数个数
templatevoid print_count() { constexpr size_t n = sizeof...(Args); // 编译期获取类型数量 std::cout << "Number of types: " << n << '\n'; } template void print_args_count(Args&&... args) { constexpr size_t n = sizeof...(args); // 编译期获取实参数量 std::cout << "Number of arguments: " << n << '\n'; }
递归展开:处理每个参数
由于不能直接遍历参数包,常用“头+尾”递归方式逐个处理。需提供非可变版本作为递归终止条件。
立即学习“C++免费学习笔记(深入)”;
- 定义空参数包的终止重载
- 定义至少一个参数的主模板,分离第一个参数(
first)和剩余参数包(rest...) - 在函数体内使用
first,再递归调用自身处理rest...
// 终止重载:空参数包
void print() {
std::cout << '\n';
}
// 主模板:至少一个参数
template
void print(const T& first, const Args&&... rest) {
std::cout << first << ' ';
print(rest...); // 递归展开剩余参数
}
// 使用
print(42, "hello", 3.14, true); // 输出:42 hello 3.14 1
折叠表达式(C++17):更简洁的展开方式
替代递归,用(expr ...)或(... expr)一次性展开并组合所有参数,支持+、&&、等运算符。
(std::cout :左折叠,等价于((std::cout-
(args + ...):右折叠,求和(要求所有类型支持+) -
(args && ...):逻辑与,全为true才返回true
templatevoid print_fold(Args&&... args) { (std::cout << ... << args) << '\n'; // 自动左折叠 } template auto sum(Args&&... args) { return (args + ...); // 要求所有参数可相加 } // 使用 print_fold("a", 1, 3.14); // 输出:a13.14 std::cout << sum(1, 2, 3, 4) << '\n'; // 输出:10
在类模板中使用:存储多个类型/值
可变参数模板类常用于实现元组(std::tuple)、类型列表或配置容器。通常结合继承或成员组合保存参数包。
简易类型容器示例(仅存类型信息,不存值):
templatestruct type_list {}; // 获取类型数量 template struct size; template struct size > { static constexpr size_t value = sizeof...(Ts); }; static_assert(size >::value == 3);
实际应用中,std::tuple、std::variant、工厂函数、日志宏等都深度依赖可变参数模板。
基本上就这些。掌握参数包声明、sizeof...、递归分解和C++17折叠表达式,就能应对绝大多数场景。









