前言:
目录
序言
(一)可变参数模板函数
1、sizeof... 运算符
(二)扩展参数包的两种方法
1、递归函数方式展开参数包
2、逗号表达式展开参数包
3、两种方法的优缺点
总结
C++11的新特性可变参数模板能够让我们可以接受可变参数的函数模板和类模板,相比
C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以这块还是比较晦涩的。现阶段呢,我们掌握一些基础的可变参数模板特性就够我们用了,所以这里我们点到为止,以后大家如果有需要,再可以深入学习。
在了解模板函数和模板类之前,我们需要先知道几个概念:
一个 可变参数模板 就是一个接收可变数目参数的模板函数或者是模板类。可变数目的参数被称为 函数包。存在两种函数包:
下面就是一个基本可变参数的函数模板:
// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template
void ShowList(Args... args)
{}
【解释说明】
与往常一样,编译器从函数的实参推倒模板参数类型。对于一个可变参数模型,编译器还会推断包中参数的数目。例如,看下面一个简单例子:
// 可变参数函数模板
template
void printArgs(Args... args)
{
cout << "Number of arguments: " << sizeof...(args) << endl;
cout << endl;
}
int main() {
printArgs(1, 2, 3); // 输出:Number of arguments: 3 Arguments: 1 2 3
printArgs("Hello", 3.14, 'c'); // 输出:Number of arguments: 3 Arguments: Hello 3.14 c
printArgs(10); // 输出:Number of arguments: 1 Arguments: 10
printArgs(); // 输出:Number of arguments: 0 Arguments:
return 0;
}
编译器会为 printArgs 实例化出以下四个不同版本,我们看下上面程序的汇编代码:
大家可以发现上述代码样例中,我使用了 sizeof... 这样的字段。那么这个是什么意思呢?
其实是 sizeof... C++11引入的一元运算符,用于获取可变模板参数包中的参数数量:
【解释说明】
【小结】
因为我们无法直接获取参数包args中的每个参数,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变参数,所以我们的用一些奇招来一一获取参数包的值。
通过递归函数方式展开参数包是一种常见的处理可变参数模板的方法。这种方法利用函数的递归调用来依次处理参数包中的每个参数。
// 递归终止函数
template
void ShowList(const T& t)
{
cout << t << endl;
}
// 展开函数
template
void ShowList(T value, Args... args)
{
cout << value << " ";
ShowList(args...);
}
int main()
{
ShowList(1);
ShowList(1, 'A');
ShowList(1, 'A', std::string("sort"));
return 0;
}
【解释说明】
在上面的示例中,ShowList 是一个展开函数模板,用于递归展开参数包并输出每个参数的值。
t
,并将其输出到标准输出流;以下是运行上述代码的输出结果:
通过递归函数方式展开了参数包,并成功输出了每个参数的值。这是一种常见的使用递归的方法来处理可变参数模板的方式。
【注意】 当定义可变参数版本的 ShowList 时,非可变参数版本必须要声明在可变参数版本 (递归体) 的作用域当中,否则会导致无限递归!!!
这种展开参数包的方式,不需要通过递归终止函数,是直接在expand函数体中展开的, printarg
不是一个递归终止函数,只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式
实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。
template
void PrintArg(T t)
{
cout << t << " ";
}
//展开函数
template
void ShowList(Args... args)
{
int arr[] = { (PrintArg(args), 0)... };
cout << endl;
}
int main()
{
ShowList(1);
ShowList(1, 'A');
ShowList(1, 'A', std::string("sort"));
return 0;
}
【解释说明】
在上面的示例中,PrintArg 是一个简单的辅助函数模板,用于打印参数的值。
main
函数中,我们调用了 ShowList 函数,并传递了不同数量和类型的参数。通过逗号表达式展开参数包,每个参数都会被依次处理,并调用 PrintArg 函数将其值输出到标准输出流。以下是运行上述代码的输出结果:
上述代码我们还可以像下述这样去进行实现操作:
【说明】
逗号表达式扩展方式和递归包扩展方式都可以用于展开可变参数模板,但它们具有不同的优缺点
具体如下:
逗号表达式扩展方式的优点:
逗号表达式扩展方式的缺点:
递归包扩展方式的优点:
递归包扩展方式的缺点:
根据具体的情况和需求,可以根据代码的复杂度和可读性的要求选择使用逗号表达式扩展方式或递归包扩展方式。逗号表达式方式适用于简单的参数展开,而递归包方式则适用于复杂的参数展开,可以更灵活地进行处理。
以上便是关于c++11 可变参数模板函数的全部知识讲解!!感谢大家的观看与支持!!!