我真的只是想写一个log函数而已。
可变参数宏(C实现)
利用头文件stdarg.h
中的宏定义:va_list
、va_start(va_list, arg)
、va_arg(va_list, type)
、va_end(va_list)
。可以实现可变参数且参数类型不同的函数。
过程:
- 函数声明中,可变参数用省略号表示。
- 创建
va_list
变量,通过va_start
访问参数列表并承接第一个参数。 - 使用
va_arg
继续获取参数的值。 - 使用
va_end
完成清理工作。
以可变参数版本的sum作为例子:
局限性:
- 可变参数宏只能实现顺序访问可变参数,无法后退访问。但可以重复使用
va_start
来初始化va_list
变量。- 运行时,函数必须能够根据已有信息(既有约定,或确定实参)确定可变参数的具体个数与类型:函数定义需要知道可变参数的具体类型、个数,这些信息是在运行时确定的,那么显然应该由实参来确定。在上面的例子中count传递了可变参数的个数,而参数类型则是既有约定(整型);
- 该方法是极不安全的,宏本身无法提供任何安全性保证,他总是按照既定代码“自作多情”的认为实参就应该是那么多,即使实参并不是那么多。这就要求所有安全性必须由程序员来保证。例如,在以上的示例代码中,如果调用时指定count为10,但实际上只给出9个可变形参,那么函数还是会读取10个参数,显然第十次读取是多余的,多余的操作一般不会有什么好结果,当然如果实参过多,多余的实参也不会被读取而是被忽略。
initializer_list标准库类型(C++11)
过程:
- 函数声明中使用
initializer_list
模板代表可变参数列表 - 使用迭代器访问
initializer_list
中的参数 - 传入参数时需要使用
{}
把多个参数括起来
|
|
局限性:
- 可变参数类型必须一致
可变参数模板(C++11)
更方便安全有效地实现可变参数且参数类型不同的函数。
过程:
- 编写含有模板参数包和函数参数包的模板函数
- 函数定义递归调用自己
- 利用函数重载(参数包含有零个参数)来处理边界情况,编写处理边界情况的模板
C++ primer 第五版中的例子:
局限性:
- 由于只能递归实现,导致需要定义重载函数来处理边界情况,代码不够清晰自然。
- 模板会为每一个不同的实例生成代码,函数的实例过多可能会使代码体积庞大。
- 依靠递归使得功能具有局限性,并且效率也会受到影响。
log函数实现
头文件:
测试代码: