格式工厂 Variadic Templates
Posted 勿在浮沙筑高台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了格式工厂 Variadic Templates相关的知识,希望对你有一定的参考价值。
版权声明:本文为博主原创文章,未经博主允许不得转载。
这次主要介绍C++11的又一个新特性 Variadic Templates (可变模板参数)
它的实现类似于initializer_list<>,它可是使类模板接受一包参数
本节主要应用递归的形式介绍 Variadic Templates
1.简单的调用
#include <iostream> #include "string" using namespace std; void printX() {}//为了响应最后一次printX()的调用,因为这次没有传递参数,如果不声明不带参数的函数会报错 template <typename T, typename... Types> void printX(const T& firstArg, const Types&... args) { cout<<firstArg<<endl; printX(args...);//递归调用 } int main() { printX(1,2,3); return 0; }
输出结果
第一次调用printX()时传递的参数为(1,一包参数) 此时输出1 ,然后递归调用printX(args...)
第二次调用printX()时传递的参数为(2,3) 此时输出结果为2,然后递归调用printX(3)
第三次调用printX()时传递的参数为(3,) 此时输出结果为3,然后调用printX() // 这就是声名不带参数的printX()的原因
2. Variadic Templates的特性调用
其实也不算Variadic Templates的特性调用,应该说所有的函数都具有这个特性
#include <iostream> #include "string" using namespace std; void printX() { cout<<"C"<<endl; } template <typename... Types> void printX(const Types&... args) { cout<<"B"<<endl; } template <typename T, typename... Types> void printX(const T& firstArg, const Types&... args) { cout<<"A"<<endl; } int main() { printX(1); printX(1,2,3,4,5); printX(); return 0; }
输出结果
总结: 编译器就喜欢调用有特点的函数(较特化的函数)...
3.举几个Variadic Templates功能的例子
a. Variadic Templates 实现类似于 printf()的 函数
#include <iostream> using namespace std; void printfA(const char *s) { while (*s) { if (*s == \'%\' && *(++s) != \'%\') throw std::runtime_error("invalid format string: missing arguments"); std::cout << *s++ << std:: endl;; } } template<typename T, typename... Args> void printfA(const char* s, T value, Args... args) { while (*s) { if (*s == \'%\' && *(++s) != \'%\') { std::cout << value << std::endl; printfA(++s, args...); // call even when *s == 0 to detect extra arguments return; } std::cout << *s++ << std::endl; } throw std::logic_error("extra arguments provided to printf"); } //~~~~~~~~~~~~~~~ int main() { int * pi = new int; printfA("%d%s%p%f\\n", 10, "abc", pi, 3.1415926 ); return 0; }
输出结果
第一次调用 printfA(%d%s%p%f\\n, 10, args...) 输出10
第二次调用 printfA(%s%p%f\\n, "abc", args...) 输出abc
第三次调用 printfA(%p%f\\n, "pi", args...) 输出[地址]
第四次调用 printfA(%f\\n, "3.1415926", ) 输出3.1415926
...
b.Variadic Templates 递归创建,递归继承
#include <iostream> using namespace std; template<typename Head, typename... Tail> class tuple<Head,Tail...>:private tuple<Tail...> { typedef tuple<Tail...> inherited; protected: Head m_head; public: tuple() {} tuple(Head v,Tail... vtail):m_head(v),inherited(vtail...){}//inheriter(vtail...)调用父类的构造函数 auto head()->decltype(m_head){return m_head;}// Head head() { return m_head;} inherited& tail() {return * this;} }; int main() { tuple<int, float, string> t{41, 6.3, "nico"}; cout<< sizeof(t) <<endl; cout<< t.head() <<endl; cout<< t.tail().head()<<endl; cout<< t.tail().tail().head() <<endl; return 0; }
输出结果
使用递归继承的方式会将这些变量的储存地址连接起来
c.sizeof...(args)的使用
#include <iostream> using namespace std; template <int IDX, int MAX, typename... Args> struct PRINT_TUPLE { static void print (ostream& os, const tuple<Args...>& t) { os << get<IDX>(t) << (IDX+1==MAX ? "" : ","); PRINT_TUPLE<IDX+1, MAX, Args...>::print(os,t); } }; // partial specialization to end the recursion template <int MAX, typename... Args> struct PRINT_TUPLE<MAX, MAX, Args...> { static void print (std::ostream& os, const tuple<Args...>& t) { } }; // output operator for tuples template <typename... Args> ostream& operator<< (ostream& os, const tuple<Args...>& t) { os << "["; PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os,t); //sizeof...(args) 会获取参数个数 return os << "]"; } int main() { cout<<make_tuple(1.5,"abc",8,10)<<endl; return 0; }
输出结果
d.递归复合
#include <iostream> using namespace std; template<typename... Values> class tup; template<> class tup<> { }; template<typename Head, typename... Tail> class tup<Head, Tail...> { typedef tup<Tail...> composited; protected: composited m_tail; Head m_head; public: tup() { } tup(Head v, Tail... vtail) : m_tail(vtail...), m_head(v) { } Head head() { return m_head; } composited& tail() { return m_tail; } }; int main() { tup<int, float, string> t1(41, 6.3, "nico"); cout << sizeof(t1) << endl; //12 cout << t1.head() << endl; //41 cout << t1.tail().head() << endl; //6.3 cout << t1.tail().tail().head() << endl; //nico return 0; }
输出结果
以上是Variadic Templates几个简单又实用的例子
如有错误请指正
参照<<侯捷 C++新标准 C++11>>
以上是关于格式工厂 Variadic Templates的主要内容,如果未能解决你的问题,请参考以下文章
来自 C++ 代码的预处理器指令 (_VARIADIC_MAX)
Variadic Macros:如何解决“宏的实际参数过多..”