本文将使用 泛型 实现可变参数。 涉及到的关见函数: std::snprintf
1、一个例子
函数声明及定义
1 // 泛型 2 template <typename... Args> 3 std::string show_str(const char *pformat, Args... args) 4 { 5 // 计算字符串长度 6 int len_str = std::snprintf(nullptr, 0, pformat, args...); 7 8 if (0 >= len_str) 9 return std::string(""); 10 11 len_str++; 12 char *pstr_out = nullptr; 13 pstr_out = new(std::nothrow) char[len_str]; 14 // 申请失败 15 if (NULL == pstr_out || nullptr == pstr_out) 16 return std::string(""); 17 18 // 构造字符串 19 std::snprintf(pstr_out, len_str, pformat, args...); 20 21 // 保存构造结果 22 std::string str(pstr_out); 23 24 // 释放空间 25 delete pstr_out; 26 pstr_out = nullptr; 27 28 return str; 29 }
2、一个调用例子
1 std::cout << "str = " << show_str("1-%s, 2-%.2f, 3-%d", "ABC", 12.3456, 100).c_str() << "\n";
3、输出结果
演示环境为: VS2015 up3
4、完整代码
1 #include <iostream> 2 3 // 泛型 4 template <typename... Args> 5 std::string show_str(const char *pformat, Args... args) 6 { 7 // 计算字符串长度 8 int len_str = std::snprintf(nullptr, 0, pformat, args...); 9 10 if (0 >= len_str) 11 return std::string(""); 12 13 len_str++; 14 char *pstr_out = nullptr; 15 pstr_out = new(std::nothrow) char[len_str]; 16 // 申请失败 17 if (NULL == pstr_out || nullptr == pstr_out) 18 return std::string(""); 19 20 // 构造字符串 21 std::snprintf(pstr_out, len_str, pformat, args...); 22 23 // 保存构造结果 24 std::string str(pstr_out); 25 26 // 释放空间 27 delete pstr_out; 28 pstr_out = nullptr; 29 30 return str; 31 } 32 33 // 入口函数 34 int main(int argc, char *argv[]) 35 { 36 std::cout << "str = " << show_str("1-%s, 2-%.2f, 3-%d", "ABC", 12.3456, 100).c_str() << "\n"; 37 38 system("pause"); 39 return 0; 40 }
5、总结
A、 new 和 delete 需要配对使用
B、可自定义日志输出格式 和 构造c++格式化字符串。 更加方便输出日志.
6、扩展 (c++11)
A、可变参数模板函数
C++11的新特性--可变模版参数是C++11新增的特性之一,它对参数进行了高度泛化,能表示0到任意个数
一个例子,其定义如下
1 // 可变参数模板函数 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 计算参数个数 6 int count_param = sizeof...(args); 7 std::cout << "参数个数=" << count_param << std::endl; 8 }
其中,计算参数个数的方式:
int count_param = sizeof...(args);
B、调用
1 // 入口函数 2 int main(int argc, char *argv[]) 3 { 4 vp_func(1); 5 vp_func("-=+", 1.23456f); 6 vp_func(1, 2.2f, "ABC"); 7 8 system("pause"); 9 return 0; 10 }
C、输出结果:
演示环境: VS2015 up3
D、解包(包展开)
有两种方式
1)、递归
2)、非递归
递归,好用,但是要考虑爆栈的情况,不推荐。这里就不介绍了。
下面介绍非递归的方式展开
2.1)、定义展开函数
1 // 参数包展开 2 template<typename T> 3 void expand(const T t) 4 { 5 std::cout << t << std::endl; 6 }
再调用展开函数
1 // 可变参数模板函数 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 计算参数个数 6 // int count_param = sizeof...(args); 7 // std::cout << "参数个数=" << count_param << std::endl; 8 9 std::initializer_list<int>{(expand(args), 0)...}; 10 // std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 11 }
2.2)、使用lambda 展开
1 // 可变参数模板函数 2 template <typename ... Args> 3 void vp_func(Args ... args) 4 { 5 // 计算参数个数 6 // int count_param = sizeof...(args); 7 // std::cout << "参数个数=" << count_param << std::endl; 8 9 // std::initializer_list<int>{(expand(args), 0)...}; 10 std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 11 }
非lambda 完整展开代码:
1 // 参数包展开 2 template<typename T> 3 void expand(const T t) 4 { 5 std::cout << t << std::endl; 6 } 7 8 9 // 可变参数模板函数 10 template <typename ... Args> 11 void vp_func(Args ... args) 12 { 13 // 计算参数个数 14 // int count_param = sizeof...(args); 15 // std::cout << "参数个数=" << count_param << std::endl; 16 17 std::initializer_list<int>{(expand(args), 0)...}; 18 // std::initializer_list<int>{([&] {std::cout << args << std::endl; }(), 0)...}; 19 }