美文网首页C语言程序园C++2.0
基于C++可变参数模板格式化字符串

基于C++可变参数模板格式化字符串

作者: 编程小世界 | 来源:发表于2019-06-16 20:29 被阅读0次

遨游于C++世界时,最讨厌的当属于对c-style的兼容 。

在格式化字符串时,通常使用的是 snprintf 这个c函数。 snprintf 是 sprintf 的安全版,能够避免缓冲区溢出。

charbuf[1024] = {0};std::strings ="Hello world";snprintf(buf,sizeof(buf),"format str: %s", s.c_str());

snprintf 接受的参数跟 printf 差不多,都是c-style的数据类型,如 %s 接受的是 const char* 类型的数据,这就需要我们将 std::string 做一个转换。这一个小小的转换让我觉得非常不爽,有没有可能让 std::string 在做某个函数的参数时能自动做转换?甚至让一个将一个普通的对象自动转换成 const char* 类型?

接下来我们将利用c++11的可变参数模板(variadic templates)、参数包(parameters pack)、完美转发(perfect forwarding)等特性来实现这一想法。

参数列表完美转发

写C++代码时,我满脑子都是怎么最大限度地提高性能。我们这次的目标也一样,在提供方便的同时,不要对性能有太大影响,甚至不影响。

首先是要将传入 fmt 函数的参数完美转发至 snprintf 。

templatestringfmt(constchar*format, Args&&... args){charbuf[128] = {0};snprintf(buf,sizeof(buf), format, convert(std::forward(args))...);returnbuf;}

这是一个可变参数模板,args表示传入的参数们。我们的思路是将传入的参数做一个转换之后传给 snprintf 。

为了原封不动的保持左右值引用,首先是用 Args&& 代替 Args 的参数类型,此处模板函数的Args需要编译器推导,所以是一个通用引用(Universal reference),可以指代左值或右值。用 std::forward<Args> 能保持参数的左右值性质,做到参数的完美转发。

自动参数转换

在 convert 这个函数中,我们要将特定的类型转换成 const char* 类型,而那些能被 snprintf 接受的类型如 int , double , char* ,则原封不动的返回。

convert 函数针对不同的参数类型需要返回不同的类型。这里也将返回值作为一个模板类型即可。

templatestructitem_return {usingtype = T&&;};

convert 函数的定义为:

templateinlinetypenameitem_return::typeconvert(T&& arg){returnstatic_cast(arg);}

convert函数默认将传入的参数原封不动的返回。接下来我们要做模板的偏特化,对于指定的对象,将其转换为const char *类型

// lvaluetemplate<>structitem_return {usingtype =constchar*;};template<>inlinetypenameitem_return::type convert(obj &arg) {std::cout<<"receive lvalue\n";returnarg.s.c_str();}// rvaluetemplate<>structitem_return {usingtype =constchar*;};template<>inlinetypenameitem_return::type convert(obj &&arg) {std::cout<<"receive rvalue\n";returnarg.s.c_str();}

注意,返回值也是需要偏特化的。

最后

我构造了一个class,hook他的两个构造函数以便于观察是否发生了拷贝。

classobj {public:strings;  obj(constchar* ss) {    s = ss;  }  obj(constobj& other):s(other.s) {printf("copy constructor\n");  }  obj(obj&& other):s(other.s) {printf("move constructor\n");    other.s.clear();  }};

之后我们使用fmt函数,就能像格式化c-style字符串一样,格式化任意一个对象啦。

intmain(){obja("haha");intb =3;std::cout<< fmt("%s %s\n%d %d", a, obj("xixi"), b,2) <

运行结果为

receivelvaluereceivervaluehaha xixi32

很好,并没有发生拷贝。

如果有想学习c++的程序员,可来我们的C/C++学习扣qun:589348389,

免费送C++的视频教程噢!

我每晚上8点还会在群内直播讲解C/C++知识,欢迎大家前来学习哦。

相关文章

  • 基于C++可变参数模板格式化字符串

    遨游于C++世界时,最讨厌的当属于对c-style的兼容 。 在格式化字符串时,通常使用的是snprintf这个c...

  • C++ 泛型编程(一) —— 可变参数模板

    可变参数模板函数 可变参数模板是 C++ 11 中引入的一个新特性,它允许我们定义一个可以接受可变数目参数的模板函...

  • ★10.关于可变参数模板

    可变参数函数模板 可变参数类模板 可变参数函数模板的使用 转发参数包

  • Python面试知识点(二)

    1、格式化字符串format和%的区别 基本语法:<模板字符串>.format(<逗号分隔的参数>) 例:要格式化...

  • day14

    可变和不可变参数 不可变类型: 类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a...

  • python语法入门二

    元组 字符串 格式化 序列 元组tuple:不可变 字符串:不可变 格式化 序列

  • 模板与泛型 —— 可变参模板

    一、可变参函数模板 二、可变参类模板 C++ 11 中引入了 可变参模板 (Variadic Template):...

  • 【C++ Templates(4)】可变参数模板

    可变参数模板示例 重载可变参数和非可变参数模板 上例也可以如下实现,如果两个函数模板只有尾置参数包不同,会优先匹配...

  • C++可变参数模板

    可变参数模板 原文链接: http://blog.csdn.net/xiaohu2022/article/deta...

  • C++11特性

    一、可变参数模板(Variadic Templates) 一、匿名函数(Lambda表达式) 二、可变模板参数 三...

网友评论

    本文标题:基于C++可变参数模板格式化字符串

    本文链接:https://www.haomeiwen.com/subject/ywfnfctx.html