Variadic Templates
1、function template:利用“参数个数逐一递减”的特性,实现递归函数调用
template <typename T, typename... Types> void func(const T& firstArg, const Types&... args) { 处理 firstArg func(args...); }
例一、实现类似 python 3 的 print()
1 void print() { cout << endl; } // 边界条件,当args为0个时调用 2 3 template <typename T, typename... Types> 4 void print(const T& firstArg, const Types&... args) { 5 cout << firstArg << ' '; 6 print(args...); 7 } 8 9 int main() { 10 print(7.5, "hello", bitset<16>(377), 42); // print "7.5 hello 0000000101111001 42" 11 return 0; 12 }
如果同时存在函数
template <typename... Types> void print(const Types&... args) { ... }
void print(const T& firstArg, const Types&... args) 与 void print(const Types&... args) 可以共存,可以编译通过。
但前者比较特化,后者比较泛化,共存时永远不会调用后者。
例二、模拟 C <cstdio> 的 printf(),引自 stackoverflow
1 void Printf(const char* s) { 2 while (*s) { 3 if (*s == '%' && *(++s) != '%') 4 throw runtime_error("invalid format string: missing arguments."); 5 cout << *s++; 6 } 7 } 8 9 template <typename T, typename... Types> 10 void Printf(const char* s, const T& firstArg, const Types&... args) { 11 while (*s) { 12 if (*s == '%' && *(++s) != '%') { 13 cout << firstArg; 14 Printf(++s, args...); 15 return; 16 } 17 cout << *s++; 18 } 19 } 20 21 int main() { 22 int* pi = new int; 23 Printf("[%p] %s = %f ", pi, "This is pi", 3.1415926); // print "[0x21fcc20] This is pi = 3.14159" 24 return 0; 25 }
2、class template:利用“参数个数逐一递减”导致“参数类型也逐一递减”的特性,实现递归继承或递归复合
例一、对 first 和 last(头尾元素)的特别处理(模板偏特化+递归)
1 // 使用tuple index和max index打印元素 2 template <int IDX, int MAX, typename... Args> 3 struct print_tuple { 4 static void print(ostream& os, const tuple<Args...>& args) { 5 os << get<IDX>(args) << (IDX + 1 == MAX ? "" : ", "); 6 print_tuple<IDX + 1, MAX, Args...>::print(os, args); 7 } 8 }; 9 10 // 递归结束的偏特化 11 template <int MAX, typename... Args> 12 struct print_tuple<MAX, MAX, Args...> { 13 static void print(ostream&, const tuple<Args...>&) {} 14 }; 15 16 // output operator for tuple 17 template <typename... Args> 18 ostream& operator<<(ostream& os, const tuple<Args...>& args) { 19 os << '['; 20 // 需要知道tuple的元素index,用sizeof...(Args)获得元素个数 21 print_tuple<0, sizeof...(Args), Args...>::print(os, args); 22 return os << ']'; 23 } 24 25 int main() { 26 cout << make_tuple(7.5, string("hello"), bitset<16>(377), 42); // print "[7.5, hello, 0000000101111001, 42]" 27 return 0; 28 }
例二、C++STL 中 tuple 的实现(类的递归继承)
template <typename... Values> class tuple; template <> class tuple<> { }; template <typename Head, typename... Tail> class tuple<Head, Tail...> : private tuple <Tail...> { typedef tuple<Tail...> inherited; public: tuple() { } tuple(Head v, Tail... vtail) : m_head(v), inherited(vtail...) { } // 调用base ctor ... protected: Head m_head; };
例三、模拟 tuple(类的递归复合)
template <typename... Values> class tup; template <> class tup<> { }; template <typename Head, typename... Tail> class tup<Head, Tail...> { typedef tup<Tail...> composited; public: tup() { } tup(Head v, Tail... vtail) : m_head(v), m_tail(vtail...) { } // 递归复合 ... protected: Head m_head; composited m_tail; };
只是这种实现 tuple 的方式内存消耗较大