在c++编程中,有时我们需要编写一些在源代码编写阶段无法确定参数个数,有时甚至无法确定参数类型的函数。
例如,一个求和函数。可以通过重载实现若干个数的和。
int sum(int i1, int i2);
int sum(int i1, int i2, int i3);
...
double sum(double d1, double d2);
double sum(double d1, double d2, double d3);
...
以上代码通过重载机制来解决变参问题。但很快我们就会发现这种方法存在的问题:必须确保所有可能的实参列表都有对应的重载声明和定义,如果上述方法如果参与运算的参数个数可能从2——20个不等,那么我们就需要重载19次同一个函数。
我们需要的是这样一类函数:它们可以在运行时取任意的实参个数并根据实参的个数自动处理不同实参的情形,或者至少可以在运行时指定任意的实参个数。
实现变参函数的三种方法
在C++中实现一个变参函数的方法有三种:第一种方法,将函数形参声明为C++11新标准中的initializer_list标准库类型;第二种方法继承自C语言,形参声明为省略符,函数实现时用参数列表宏访问参数;最后一种方法利用C++泛型特性,声明一个可变参数模板来实现。
1. 可变参数宏
实现步骤如下:
1. 函数原型中使用省略号;
2. 函数定义中创建一个va_list变量;
3. 初始化va_list变量;
4. 访问参数列表;
5. 完成清理工作;
上述步骤的实现需要使用到四个宏:
va_list、va_start(va_list, arg)、va_arg(va_list, type)、va_end(va_list)
这些宏在
头文件stdarg.h
中声明定义。因此使用时需要包含该头文件。
以下代码使用可变参数宏实现一个函数sum,该函数接受任意个数的整形实参,返回这些实参的和。(忽略可
本文实例展示了
C++
可变参数
的
函数
与
模板
的实现方法,有助于大家更好的理解
可变参数
的
函数
与
模板
的应用,具体内容如下:
首先,所谓
可变参数
指的是
函数
的参数个数可变,参数类型
不定
的
函数
。为了编写能处理不同数量实参的
函数
,
C++
提供了两种主要的方法:如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型;如果实参的类型不同,我们可以编写
可变参数
模板
。另外,
C++
还有一种特殊的省略符形参,可以用它传递可变数量的实参,不过这种一般只用于与C
函数
交互的接口程序。
一、
可变参数
函数
1、initializer_list形参
如果
函数
的实参数量未知但是全部实参的类型都相同,我们可以
C++
编程中实现
可变参数
函数
有多种途径,本文介绍一种最常见的实现途径,即
可变参数
宏方法:形参生命为省略符,
函数
实现时用
参数列表
宏访问参数。
1.
可变参数
宏实现
变参
函数
可变参数
宏实现可分为以下几个步骤:
函数
形参原型中给出省略符;
函数
实现中声明一个va_list
可变参数
列表变量;
开始初始化构造va_list变量;
访问
变参
列表;
完成清理工作;
上述步骤的实现需要使用到四个宏:
va_list
void va_start(va_list ap, last_arg)
type va_arg (va_list ap, type)
void va_end(v
可变参数
的实现要解决三个问题:
1.如何调用带有
可变参数
的
函数
2.如何编译有
可变参数
的程序3.在带有
可变参数
的
函数
体中如何持有
可变参数
第一个问题, 调用时在可以传入
可变参数
的地方传入
可变参数
即可,当然,还有一些需要注意的地方,后面会提到。
第二个问题,编译器需要在编译时采用一种宽松的检查方案,,这会带来一些问题, 比如对编程查错不利。
第三个是我在这里要关心的问题,先以C语言为例分析其实现原理。
printf和scanf是C语言标准库中最常见的
可变参数
函数
, printf的签名是
代码如下:int printf(const char* format, …);
其中,… 表示
可变参数
,现在模仿
1、可
变参
函数
的原理C/
C++
函数
的参数是存放在栈区的,并且参数的入栈是从参数的右边开始,即最后一个参数先入栈,而第一个参数最后才入栈,所以,根据栈的后进先出性质,
函数
总能找到第一个参数。所以,可
变参
函数
的实现必须能够从已知参数中获取到
函数
所需要参数的个数;
例如printf
函数
,第一个参数就是一个格式串,而后面所需要的参数个数能够从格式串中得到。 2、可
变参
函数
的设计标准头文件stdarg.h
一个
可变参数
模板
(variadic template)就是一个接受可变数目参数的
模板
函数
或
模板
类。存在两种参数包:
模板
参数包(template parameter packet),表示零个或多个
模板
参数;说到这里,ubuntu(linux) 默认栈大小8M(使用命令 ulimit -a查看), Win下,Visual Studio 默认栈大小1M(连接器->系统)。
函数
参数为参数包的形式,使用递归展开。从本质上讲,逗号的作用是将一系列运算按顺序执行。整个逗号表达式的值为系列中最后一个表达式的值。
可变参数
模板
是
C++
11新增的最强大的特性之一,它对参数高度泛化,能够让我们创建可以接受
可变参数
的
函数
模板
和类
模板
。在
C++
11之前,类
模板
和
函数
模板
中只能包含固定数量的
模板
参数,可变
模板
参数无疑是一个巨大的改进,但由于
可变参数
模板
比较抽象,因此使用起来需要一定的技巧。在
C++
11之前其实也有
可变参数
的概念,比如printf
函数
就能够接收任意多个参数,但这是
函数
参数的
可变参数
,并不是
模板
的
可变参数
。
有时候需要写
不定
个数参数的
函数
。就像c语言的sprintf
函数
。
函数
申请方法是比较固定的:
return-type functionName( [type t1] …)
比如: void fun(…);
int printf ( const char * format, … );省略号的位置就是
不定
个数的
参数列表
了。
接下来,给出常见的3种写法:方法1知道数据的具体类型时
方法2使用va_star