您的位置:首页 > 编程语言 > C语言/C++

C++模板实现printf

2016-02-24 23:29 423 查看
要函数实现接受可变的参数模型,有三种方法。

第一,通过C语言的va_list结构,以及va_start、va_arg、va_end来实现。

如:

void print(char *msg, ...)
{
va_list args;
va_start(args, msg);
...

int a = va_arg(args, int); //这里可以是int/double等等类型,根据msg来判断。

...
va_end(args);
}


第二,通过c++的initializer_list模板,但接受的参数类型必须一致。

如:

void func(initializer_list<std::string> sl);


调用

func(str1);
func(str1, str2);

第三,通过c++ 模板可变参数实现。

实现printf具体如下(只讨论输出int数据的情况):

【相关知识:模板、函数重载、特例化】

基本思路是通过模板的递归调用,将参数包的参数一个个取出来取代string里的%d输出符号。

#include <iostream>
#include <string>
using namespace std;

/×
函数1.
这个函数要定义,若不定义问题出现如图1.
和模板的实例化有关,在my_printf中sizeof...(args) == 0 的时候依然实例化了if条件的调用,为什么这样?我也不清楚了。
×/
 int pri_print(string &str)
{
cout << "1 -> ";
return 1;
}

 /×
模板2.
此模板比模板3更具特例化,故可打破模板3的无限递归。
×/
 template<typename t2>
int pri_print(string &str, const t2 &elem)
{
cout << "2 -> ";
auto index = str.find_first_of("%");
if (index == string::npos)
return 0;

char num[16];
sprintf(num, "%d", elem);
str.replace(index, 2, num);

return 1;
}

 /×
模板3.

×/
 template<typename t2, typename ... Args>
int pri_print(string &str, const t2 &elem, const Args& ... args)
{
cout << "3 -> ";
auto index = str.find_first_of("%");
if (index == string::npos)
return 0;

char num[16];
sprintf(num, "%d", elem);
str.replace(index, 2, num);

pri_print(str, args...);
return 1;
}

/×
针对输出函数的第一个语句是const char *的类型,也结合上面三个函数的实现方法,故抽出再定义一个函数,其第一个参数类型为const。
注意:以上函数第一个参数不是const的。
×/
 template<typename ... Args>
int my_printf(const string &str, const Args& ... args)
{
string str_1(str);

// ...
if (sizeof...(args) != 0)
pri_print(str_1, args...);

cout << str_1;
return 1;
}

int main(int argc, char *argv[])
{
int a = 666;
int b = 777;
int c = 888;
// 输出结果如: 图2
my_printf("I am just a sentence\n");
my_printf("Here a = %d\n", a);
my_printf("Here a = %d, b = %d\n", a, b);
my_printf("Here a = %d, b = %d, c = %d\n", a, b, c);

return 0;
}



图1



图2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: