Variadic Template

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 << "\t" << 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;
}
posted @ 2020-11-18 21:05  Codroc  阅读(146)  评论(0编辑  收藏  举报