初次接触讲STL的书,翻来翻去,满眼就看到两个字“泛型”。认真学习一番之后,终于从最初的一头雾水,到现在的稍微有些领悟。
个人感觉,应该先从第三章开始看,即:Iterator。这一章讲的内容贯穿全书。其实这章并不是只讲Iterator,而且也没把Iterator讲完,却一直在讲type——型别,认真读完之后,感觉学到了很多新东西,包括语法层面到设计模式。
首先,Iterator本身是一种设计模式,在Design Patterns一书中P171~P181有介绍,但是那本书出现的太早了,导致上面的例子被STL源码剖析当作反例来讲。Iterator这一章的重要性在于它出现在一个矛盾点上——全书出处体现的泛型思想,本章却在翻来覆去的讲型别;全书都在泛化,本章却一直描述特化。为什么会这样呢?因为我们打开了“泛化”的窗户的同时,不可避免的进来了一些苍蝇。泛型思想讲究对所有的型别作出统一的接口,使我们能够以统一的方式去对不同的型别调用相同的算法。可是型别究竟还是不同的,为了提高运行的效率,真正实现的算法应该能够对不同的型别进行区分,选择最有利的解决办法,避免“过分的一碗水端平”导致“要么最好要么最差”的运行效率。在这种情况下,Algorithms和Containers的结合点:Iterators面临来自效率的挑战。我们都知道,Algorithm都是以Container的Iterator为传入参数的,这是泛型化设计的典型体现。因此Iterator本身是泛化的产物,此时必须承担起特化的任务,做到:
- 能够触发Algorithms选择最优算法的条件
- 不影响Containers的简洁高效
那么,Iterator是怎么做到的呢,简单的说,就是:
- 从Container中获得型别,因为Iterator本身是Container的内嵌型别,这一点很容易实现;
- 在外部独立定义所有算法所需要的标签,如copy算法的has_trivial_default_constructor、fill算法的is_POD等等;
- 在每一个class中,根据自己的实际情况,将这些标签选择性的声明为内嵌型别;
- 建立型别萃取机,同时设定默认的标签;
- 对部分POD或者prime type进行特化,设定最优标签;
- 在算法实现时,由总函数调用型别萃取机,通过“重载”机制,激活最优算法,从而完成最优算法的选择过程。
该过程中没有标志变量,以“型别”为“参数”,巧妙的利用重载机制,将弱类型语言转换成了一个能够逆向识别类型的语言。
1 #include <iostream> 2 using namespace std; 3 struct is_int_tag{}; 4 struct not_int_tag{}; 5 struct is_int_ptr_tag{}; 6 7 template <class T> 8 struct type_traits 9 { 10 typedef not_int_tag type_tag; 11 }; 12 13 template<> 14 struct type_traits<int> 15 { 16 typedef is_int_tag type_tag; 17 }; 18 template<> 19 struct type_traits<int*> 20 { 21 typedef is_int_ptr_tag type_tag; 22 }; 23 24 template <class T> 25 void func_aux(T t, is_int_tag) 26 { 27 cout<<"this is an int : " << t <<endl; 28 } 29 template <class T> 30 void func_aux(T t, not_int_tag) 31 { 32 cout<<"this is not an int !"<< endl; 33 } 34 template <class T> 35 void func_aux(T t, is_int_ptr_tag) 36 { 37 cout<<"this is an int_ptr : "<< *t <<endl; 38 } 39 template <class T> 40 void func(T t) 41 { 42 typedef typename type_traits<T>::type_tag type_tag; 43 func_aux(t, type_tag()); 44 } 45 46 template <class U, class T> 47 void deducation_aux(U u, T t) 48 { 49 T new_variable = *u; 50 cout<<"type was deducated ! "<< new_variable <<endl; 51 } 52 template <class T> 53 void deducation(T t) 54 { 55 deducation_aux(t, *t); 56 } 57 58 int main() 59 { 60 //type_traints 61 int i = 3; 62 func(i); 63 char c = 'c'; 64 func(c); 65 int* p; 66 *p = 4; 67 func(p); 68 //argument deducation of function template 69 deducation(p); 70 return 0; 71 }