> 文章列表 > C++编程之 可变参数模板

C++编程之 可变参数模板

C++编程之 可变参数模板

文章目录

C++11引入了可变参数模板(Variadic Templates),可以让函数和类模板接受可变数量的参数,从而更灵活地处理不同的输入。

模板参数包

可变参数模板的语法是在模板参数列表中使用省略号(…)表示可变数量的参数。在函数或类模板中,使用参数包展开(Parameter Pack Expansion)语法来访问这些参数。

下面是一个示例代码,展示了一个使用可变参数模板的函数模板,它可以计算任意数量的整数的总和:

template<typename... Args>
int sum(Args... args)
{return (args + ...);
}

在这个函数中,我们使用了模板类型参数包typename… Args和函数参数包Args… args来定义一个可变参数模板函数。参数包Args将会包含任意数量和类型的参数,并且可以在函数体中进行类型安全的操作。函数体中的(args + …)使用了展开语法,将参数包中的所有参数相加。

下面是一个调用sum函数的示例代码:

int result = sum(1, 2, 3, 4, 5); // result = 15

在这个示例中,sum函数的参数列表包含了5个整数,但它也可以接受任意数量的整数作为输入。

另一个常见的使用可变参数模板的场景是创建类型安全的可变参数函数。例如,下面的示例代码演示了一个使用可变参数模板实现的printf函数:

template<typename... Args>
void print(Args... args) {(std::cout << args << " ", ...); // 将args中的每个元素展开到语句中
}
  1. 在展开语法中,逗号操作符通常用于将展开语法的左侧部分与右侧部分组合在一起,以实现一些特定的行为。因此,如果在展开语法中省略逗号操作符,则可能会导致编译器无法正确解析代码,从而产生错误。
  2. 在这个例子中,如果省略逗号操作符,则代码将无法通过编译。因为展开语法的左侧部分(std::cout << args << " ")需要与右侧部分(…)组合在一起,以实现将参数包展开成一系列参数并将它们插入到输出流中的效果。
  3. 因此,在这个例子中,逗号操作符是必需的,不能省略。如果省略逗号操作符,则代码将无法正确解析,并且会产生编译错误。

在这个函数中,我们使用展开语句来展开args参数包,将参数包中的每个元素展开成一个独立的语句std::cout << args << " "。由于我们使用了可变参数模板,因此我们可以在函数调用时传递任意数量和类型的参数,并保持类型安全。例如:

print(1, "two", 3.14, '4');

这个函数调用将会输出1 two 3.14 4,而且不会存在类型安全问题。因此,可变参数模板可以创建类型安全的可变参数函数。

参数包展开语法

参数包展开语法是C++11中引入的一种新特性,用于展开可变数量的参数包。在C++中,参数包是一组类型或值的集合,由“…”语法来定义,例如typename… Args表示一个类型参数包,int… values表示一个值参数包。

  1. 模板参数包展开
template <typename... Args>
void my_func(Args... args) {(std::cout << ... << args) << std::endl;
}

在这个函数中,我们使用了折叠表达式 (std::cout << … << args),其中省略号 … 表示将所有参数展开成一个序列,并使用二元操作符 << 将它们连接在一起输出到 std::cout。

在这里使用到了二元左折叠的 折叠表达式(可看另一篇文章介绍C++17编程之 折叠表达式):
std::cout为初始值,args为参数包
std::cout << … << args 展开就是 ((std::cout << E1) << E2) << … << EN
E1 … EN为实际的元素值

  1. 模板参数包展开(使用递归)
template <typename T>
void my_func(T t) {std::cout << t << std::endl;
}template <typename T, typename... Args>
void my_func(T t, Args... args) {std::cout << t << ", ";my_func(args...);
}

在这个例子中,my_func使用递归展开参数包。第一个函数接受单个参数并将其打印到标准输出,第二个函数接受多个参数,并依次将它们打印到标准输出,直到所有参数都被处理完毕。