用C++可变参数模板实现类似C语言的printf

来源:互联网 发布:linux is a directory 编辑:程序博客网 时间:2024/06/06 03:47

在以前,C++要实现可变参数的函数,得用C语言的va_list那一套东西,直到C++11的可变参数模板诞生,正好最近在写一个日志模块,是时候了解一下可变参数模板了。

下面这个简单的Log函数,只使用##进行占位,并没有区分类型,有点像C#的{0}、{1}……

#include <iostream>#include <sstream>#include <string>template<typename ...Args>void mylog(const std::string& format, const Args&... args) {std::string temp(format);mylog(temp, args...);}template<typename Next, typename ...Other>void mylog(std::string& format, const Next& next, const Other&... other) {auto index = format.find_first_of("##");if (index == std::string::npos) {mylog(format);}else {std::ostringstream oss;oss << next;format.replace(index, 2, oss.str());mylog(format, other...);}}void mylog(std::string& format) {std::cout << format;}int main() {// 无占位符mylog("Hello Indian Mi fans!\n");// 有占位符mylog("Do you like Mi##?\n", "4i");// 占位符超过参数数量,多余的占位符原样输出mylog("My name is ####!\n", "Stephen");// 参数数量超过占位符数量,多余的参数被忽略mylog("## is ## years old, ## meters tall.\n", "Stephen", 18, 1.75f, "useless", "useless");// 参数不能被格式化为字符串,发生编译错误//mylog("Here comes a compile error ##\n", std::cout);return 0;}

运行结果:


可以看到,一共有三个版本的mylog函数,前两个都是模板函数,第一个函数用来将const的格式化字符串简单地转换为非const形式的调用,第二个函数则是核心,用某种规则进行递归,第三个函数则是递归出口。

要注意的是:

1. Args...可以是任意数量个参数,包括0个。

2. args...形式的参数包只能通过递归的方式解开。

3. 用sizeof...(args)可以得到此参数包的参数个数。

4. 宏替换有效:#define DEBUG(format, ...) mylog(format, ##__VA_ARGS__)。

原创粉丝点击