本文将使用 泛型 实现可变参数。 涉及到的关见函数:  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 }

c++之可变参数格式化字符串(c++11可变模板参数)的更多相关文章

  1. 零值初始化&字符串常数作为函数模板参数

    1.在定义一个局部变量时,并希望该局部变量的初始化一个值,可以显示调用其默认构造函数,使其值为0(bool类型默认值为false). template <typename T> void ...

  2. Tostring(); 括号中的参数 格式化字符串

    最近在逛 msdn 发现    查到  getTypeCode 方法  看到里边居然有 tostring("D")这样的写法      运行了一遍 感觉可以显示值      然后就 ...

  3. C语言之可变长参数格式化

    概述 本文演示环境: win10 + Vs2015 可变长参数格式化 两个概念: 1. 参数长度不定, 2. 参数格式化. 使用函数 vsnprintf 结合 va_list. 源码 写好了函数, 照 ...

  4. C++ 11可变参数接口设计在模板编程中应用的一点点总结

    概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...

  5. [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇

    目录 [二进制漏洞]PWN学习之格式化字符串漏洞 Linux篇 格式化输出函数 printf函数族功能介绍 printf参数 type(类型) flags(标志) number(宽度) precisi ...

  6. Linux下的格式化字符串漏洞利用姿势

    linux最早的漏洞防护机制nx-stack刚刚出现后就有人想出了突破方法.那就是只有栈是不可执行,而除了栈以外的其他地方还是可以执行的,只要把返回地址执行别的地方就可以. 一.格式化字符串漏洞 格式 ...

  7. C++ Templates(1.3 多模板参数 Multiple Template Parameters)

    返回完整目录 目录 1.3 多模板参数 Multiple Template Parameters 1.3.1 为返回类型设置模板参数参数 Template Parameters for Return ...

  8. 《深入实践C++模板编程》之三——模板参数类型详解

    非类型模板参数 和 模板型模板参数 整数以及枚举类型:指向对象或者函数的指针:对对象或函数的引用:指向对象成员的指针.统称为非类型模板参数. 模板型模板参数,是指模板参数还可以是一个模板.   1.整 ...

  9. c(++)可变参数之格式化字符串

    0.序言 使用printf函数,其参数就是可变参数.下面将使用 C语言  的库函数实现可变参数的函数 . 用途(欢迎补充): A.记录日志,可能需要将变量格式化输出到日志文件. B.格式化字符串,显示 ...

随机推荐

  1. C语言小练习 微型学生管理系统

    很简陋,没有做输入校验,以写出来为第一目的,中间出了不少问题,尤其是结构体内字符串赋值的时候(理解不透彻),字符串比较用strcmp不能直接==判定,逻辑也很重要,不然会出现莫名其妙的问题. 涉及知识 ...

  2. 学习Java的第四天

    一.今日收获 1.java完全手册的第一章 2.   1.6节了解了怎么样用记事本开发java程序 与用Eclipse开发 2.完成了对应例题 二.今日难题 1.一些用法容易与c++的混淆 2.语句还 ...

  3. Swift-技巧(十一)重写运算符

    摘要 基础数据的运算可以直接使用四则运算符.在 Swift 中也可以通过重写四则运算符的方式,让 struct 或者 class 创建的结构体或者对象也能像基础数据那样直接使用四则运算符. Swift ...

  4. day07 MySQL索引事务

    day07 MySQL索引事务 昨日内容回顾 pymysql模块 # 链接数据库都是使用这个模块的 # 创建链接 import pymysql conn = pymysql.connect( host ...

  5. Ubuntu Linux安装QT5之旅

    1. QT 版本选择 如何选择QT版本,参考如下介绍 https://www.cnblogs.com/chinasoft/p/15226293.html 2.  在此以5.15.0解说 下载QT 版本 ...

  6. Hive(十二)【调优】

    目录 1.Fetch抓取 2.本地模式 3.表的优化 3.1大小表join 3.2大表Join大表 3.3map join 3.4group By 3.5 count(distinct) 3.6笛卡尔 ...

  7. 零基础学习java------day12------数组高级(选择排序,冒泡排序,二分查找),API(Arrays工具类,包装类,BigInteger等数据类型,Math包)

    0.数组高级 (1)选择排序 它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的起始位置 ...

  8. What all is inherited from parent class in C++?

    派生类可以从基类中继承: (1)基类中定义的每个数据成员(尽管这些数据成员在派生类中不一定可以被访问): (2)基类中的每个普通成员函数(尽管这些成员函数在派生类中不一定可以被访问): (3)The ...

  9. C++ default constructor | Built-in types

    Predict the output of following program? 1 #include <iostream> 2 using namespace std; 3 4 int ...

  10. Dubbo服务调用超时

    服务降级的发生,其实是由于消费者调用服务超时引起的,即从发出调用请求到获取到提供者的响应结果这个时间超出了设定的时限.默认服务调用超时时限为1秒.可以在消费者端与提供者端设置超时时限. 一.创建提供者 ...