c/c++可变参数列表

1. c语言的可变参数列表

va_list ptr: 定义一个指向可变参数列表的指针
va_start(ptr, a):初始化指针,其中第二个参数为函数可变参数列表之前的固定参数
va_arg(ptr,int):取出指针指向的元素,第二个参数为元素的类型,返回值为取出的元素,同时指针后移。
va_end(ptr) : 还原ptr指针

#include<stdarg.h>
// 确定:要知道有多少个参数,并且要知道每个参数的类型
void print(int a, ...)
{
	va_list ptr; // 定义一个指向可变参数的指针
	va_start(ptr, a); // 初始化指针,使得指针指向固定参数a后面的可变参数列表
	int tmpInt = va_arg(ptr, int); // 取指针指向的可变参数,类型为int; 同时ptr向后移动
	char tmpChar = va_arg(ptr, char);  // 取当前指向的类型为char
	va_end(ptr);
	cout << tmpInt << ", " << tmpChar << endl;
}
int main()
{
	print(3, 3, 'a');
	getchar();
	return 0;
}

弊端,必须要知道可变参数的个数和参数类型

  • c语言的printf也是这样实现的, printf根据format中的%u,%d等信息可以得出有几个可变参数,每个可变参数的预期类型是啥。
_Check_return_opt_   
_CRT_STDIO_INLINE  int __CRTDECL printf( _In_z_ _Printf_format_string_ char const* const _Format, ...)

VA_ARGS:
C99新增的宏,用来替换宏定义中的可变参数列表

#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)
LOG("%d, %c", 2, 'x');  //  2 x

#define LOG2(x) printf("LOG2 "#x" %d \n", x);  // #会吧参数转换成字符串
int tmpInt = 100;

LOG2(55);  // LOG2 55 55
LOG2(value);   // LOG2 Value 100 

// ##当可变参数为0时去掉逗号和后面的数据 
#define LOG_TYPE(format, ...) do{       \
        printf(format, ##__VA_ARGS__);  \
                                        \
} while(0)

# 将变量转化成字符串
## 用于宏中的参数替换, 如 #define test(x) f(a##x) . test3 => f(a3)

#include <stdio>
#define MODEL_NAEM      "model_name"
#define err_print(fmt, ...) \
printf("[ERROR!] ["MODEL_NAEM": (fun)%s, (line)%d] " fmt, __func__, __LINE__, ##__VA_ARGS__)
// 注意fmt和前面字符串之间的链接方式
int main(void){
    err_print("i = %d\n", 5);
    return 0;
}

2. c++ 可变参数列表

  • 2.1可变模板参数函数
    • 递归方式解包
#include<iostream>
#include<string>
using namespace std;
// 递归结束
template<typename T>
void showOne(T t)
{
	cout << t << endl;
}

template<typename T, typename...Ts>
void showOne(T t, Ts... ts) 
{
	cout << t << ", ";
	showOne(ts...);
}

template<typename... T>
void show(T... ts)
{
	showOne(ts...);
}

int main()
{
	string s("dddd");
	show("int", 2, 2.32, s); 
}

const 引用版本

template<typename T>
void disPlayOne(T t) 
{
	cout << t << endl;
}

template<typename T1, typename... Ts>
void disPlayOne(const T1 &t1, const Ts&... ts)
{
	cout << t1 << ", ";
	disPlayOne(ts...);
}

template<typename... T>
void disPlay(const T&... ts)
{
	disPlayOne(ts...);
}
int main()
{
	string s("dddd");
	disPlay("int", 2, 2.32, s); 
}

右值引用版本

#include<iostream>
#include<memory>
#include<string>

using namespace std;

template<typename T>
void print(T &&t)
{
	cout << t << endl;
}

template<typename T>
void  printargs(T &&arg)
{
	print(forward<T>(arg));
}

template<typename T, typename... Ts>
void printargs(T &&arg, Ts&&... args)
{
	print(forward<T>(arg));
	printargs(forward<Ts>(args)...); // 注意转发时候的书写格式
}


int main()
{
	char ch = 'a';
	string ss("abc");
	printargs(1, 34, 52, ch, ss);
	return 0;
}
  • 逗号方式解包

#include<iostream>
#include<memory>
#include<string>
#include<initializer_list>

using namespace std;

template<typename T>
void print(T &&t)
{
	cout << t << endl;
}
template<typename... Ts>
void expand(Ts... ts)
{
	int arr[] = {(print(ts),0)...};  // 会被展开为 {(print(ts1), 0), (print(ts2), 0), (print(ts2), 0), ...}
	//或者改进为std::initializer_list<int>{(printarg(args), 0)...};
	//用lambda表达式实现(gcc4.8.6编译报错)
	std::initializer_list<int>{([&] {cout << args << endl; }(), 0)...};
}

int main() 
{
	expand(1, 2, 4, 'a', "ddfa");
	return 0;
}

  • 2.2 可变参数模板类
    • 递归方式解包
template <typename... Ts>
class ClassA;
// 可变参数模板类可以携带多个不同的参数
ClassA<int>
classA<int, char>
ClassA<> 
//----------------------------

// 前向声明
template <typename... Ts>
class ClassTs;

// 特化处理,递归终止函数
template <typename T>
class ClassTs<T>
{
public:
	enum { value = sizeof(T) };
};

template <typename T, typename... Ts>
class ClassTs<T, Ts...>
{
public:
	enum { value = ClassTs<T>::value + ClassTs<Ts...>::value };
};

int main()
{
	cout << ClassTs<int, char, char, int>::value << endl;
	return 0;
}

参考:
c++11——可变参数模板
C 语言 define 变参__VA_ARGS__使用
#、##、__VA_ARGS__和##__VA_ARGS__的作用
c++反射机制
c++可变参数模板


备注:之后看了模板再来补充

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值