Variadic Template
谈的是 template
- function template
- class template
变化的是 template parameters
- 参数个数 (variadic number) --- 利用参数个数逐一递减的特性,实现递归函数调用,使用 function template 完成
- 参数类型 (different type) --- 利用参数个数逐一递减的特性导致参数类型逐一递减,实现递归继承或递归复合,用 class template 来完成
void func() {···}
template<typename T, typename ... Types>
void func(const T& firstArg, const Types& ... args) {
//处理 firstArg
func(args ...);
}
利用 function template 来实现函数递归,令函数参数逐一递减,如下:
#include <iostream>
using namespace std;
void print() {
}
template<typename T, typename ... Types>
void print(const T& firstArg, const Types& ... args) { // 1
print(args ...);
cout << firstArg << " " << sizeof ... (args) << endl; // sizeof ... (args) 可以得知这一包东西 (args) 中还有几个参数。
}
int main(){
print(12, 2.2, "hello variadic template!", 'a');
return 0;
}
如果还有另外一个长的差不多的函数,编译器会报错嘛?
template<typename ... Types>
void print(const Types& ... args) { // 2
···
}
看似 1 与 2 差不多,那么 print(args ...); 到底是调用 1 还是调用 2 呢?这就要看哪个更加特化,哪个更加泛化。如果使用模板形成了 overload,那么会优先调用更加特化的那个。
答案是 print(args ...); 会调用 1,也就是说 1 更加特化。我的理解是参考了老子的 “一生二二生三三生万物” 这句话,从这句话中来讲,“一” 是包罗万象的,也就是最泛化的,所以函数 1 更加特化。
若参数 type 皆同,用 initializer_list 足矣
#include <iostream>
using namespace std;
struct iterator_less{
template<typename _ForwardIterator>
bool operator()(_ForwardIterator _it1, _ForwardIterator _it2) const {
return *_it1 < *_it2;
}
};
template<typename _ForwardIterator, typename _Compare>
_ForwardIterator _elem_max(_ForwardIterator first, _ForwardIterator last, _Compare cmp) {
if(first == last) return first;
_ForwardIterator result = first;
while(first != last) {
if(cmp(result, first)) {
result = first;
}
++first;
}
return result;
}
template<typename _ForwardIterator>
_ForwardIterator elem_max(_ForwardIterator first, _ForwardIterator end) {
return _elem_max(first, end, iterator_less());
}
template<typename T>
T max(initializer_list<T> _l) {
return *elem_max(_l.begin(), _l.end());
}
// 测试!
int main(){
int max_elem = max({23,1,2,55,6,7,8888}); // 通过 initializer_list 的接口
cout << "max elem: " << max_elem << endl;
return 0;
}
如果我不想用 initializer_list 的接口呢?
接下来就是利用 function template 来实现函数递归调用来使参数逐个递减,最后来调用 std::max(arg1, arg2);
template<typename T>
T maximum(T obj) {
return obj;
}
template<typename T, typename ... ArgsType>
T maximum(const T& firstArg, const ArgsType& ... args) {
return std::max(firstArg, maximum(args ...));
}
用于递归继承 (recursive inheritance)
递归调用处理的都是参数,使用 function template
递归继承处理的是类型,使用 class template
template<class ... Types>
class tuple;
template<>
class tuple<> {};
template<class Head, class ... Tail>
class tuple<Head, Tail...> : private tuple<Tail...>{
public:
tuple() {}
tuple(Head first, Tail... tails) : _obj(first), tuple<Tail...> (tails...) {}
Head head() { return _obj; }
tuple<Tail...> tail() { return *this; }; // 这里为什么返回 *this ? 需要之后去看书理解,也就是继承类的对象模型到底是长什么样?
private:
Head _obj;
};
int main(){
tuple<int, string, double> t(3, "hello", 3.3);
cout << t.head() << endl;
cout << t.tail().head() << endl;
return 0;
}