C++如何使用可变参数模板(Variadic Templates)?(代码示例)

12次阅读

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

C++如何使用可变参数模板(Variadic Templates)?(代码示例)

可变参数模板是C++11引入的重要特性,用于编写能接受任意数量、任意类型参数的模板函数或类。核心在于参数包(parameter pack)和展开操作(...)。

基本语法:声明与展开

typename...class...声明类型参数包,用Args...声明形参包。展开时args...会将参数依次代入上下文。

最简示例:打印参数个数

template void 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
template void 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)、类型列表或配置容器。通常结合继承或成员组合保存参数包。

简易类型容器示例(仅存类型信息,不存值):

template struct type_list {};  // 获取类型数量 template struct size;  template struct size> {     static constexpr size_t value = sizeof...(Ts); };  static_assert(size>::value == 3);

实际应用中,std::tuplestd::variant、工厂函数、日志宏等都深度依赖可变参数模板。

基本上就这些。掌握参数包声明、sizeof...、递归分解和C++17折叠表达式,就能应对绝大多数场景。

text=ZqhQzanResources