什么是可变参数模板?
相信你用过普通的模板函数,也就是这样。
template<typename T>
void func()
{
...
}
可变参数模板的写法就是在这个基础上稍加改进,在参数前边加上三个点。这里说明一下可变参数模板如何取出参数的值,因为参数是可变的,所以,可以写成这个样子—— 一个头部分,和一个可变参数部分。函数实现的时候使用递归的方式将值一一取出。
所以模板的声明大致是这样。
template<typename THead,typename ...T>
void func()
{
...
}
下面写点东西实践一下。
template <typename Harg,typename... Args>
void mySplicing(char *buf,Harg arg,Args ... args)
{
//todo 将输入的参数拼接在一起,放到 buf中
memcpy(buf,arg,strlen(arg));
buf += strlen(arg);
mySplicing(buf,args...);
}
按照上面的声明我门就得到了一个可以拼接多个任意字符的函数。事情真的解决了吗?仔细思考就会发现问题了,如果可变参数部分只有一个值,那么我们的函数并没有对应的实现。另外我们肯定也希望函数会在可变参数只有一个时停止递归。所以要实现这样的一个函数。
template <typename Harg>
void mySplicing(char *buf,Harg arg)
{
memcpy(buf,arg,strlen(arg));
buf += strlen(arg);
return;
}
运行一下
int main ()
{
char *buf = new char[128];
mySplicing(buf,"a","b","c","d");
std::cout<<buf<<std::endl; //输出 abcd
}
有了以上的经验接下来就可以尝试实现类似CString中的format()功能了。虽然c++中依然可以用sfprintf()实现功能。但是谁能拒绝造无意义的轮子呢?尤其时在摸鱼时间内……
void myFormat(std::string &target,const char * content)
{
std::string add(content);
target.append(add);
return ;
}
template<typename Thead,typename... Types>
void myFormat(std::string &target,const char *content,Thead arg ,Types ... args)
{
while(*content)
{
char a ,b;
if(a = *content == '%' && (b = *++content )!= '%')
{
if(b == 'd')
{
int x;
memcpy(&x,&arg,sizeof(int));
target.append(std::to_string(x));
// std::cout<<"添加一个整数"<<x<<std::endl;
}
else if(b == 's')
{
int len = strlen((const char *)arg);
char * buf = new char [len+ 1];
memset(buf, 0, len);
memcpy(buf,(const char *)arg,len);
target.append(buf);
delete []buf;
buf = nullptr;
// std::cout<<"添加一个字符"<<arg<<std::endl;
}
myFormat(target,++content,args...);
return;
}
else
{
char add ;
memcpy(&add,content++,sizeof(char));
target.push_back(add);
// std::cout<<"添加一个字符"<<add<<std::endl;
}
}
}
int main ()
{
std::string str;
myFormat(str,"[%s][%d],[%d],[%d],[%d]","fromat",1,2,3,4);
std::cout<<str<<std::endl;//[fromat][1],[2],[3],[4]
return 0;
}