- 总结
尽管现在的很多语言支持参数类型的判别,但是c/c++并不支持这一特性。
但是我们可以通过一些技巧使得c++具有自动判别参数类型的特性。
- 模板
我们都知道在模板类和模板函数中我们不用具体指定参数的型别,编译器会自动的判别参数的类型。
所以我们想可不可以把编译器运行时所确定的型别萃取出来呢?
可以通过内嵌型别实现。
#include <iostream> using namespace std; template <class T> struct MyIter{ typedef T value_type; //声明内嵌型别为value_type T* ptr; MyIter(T* p = 0):ptr(p){ } T& operator*()const{ return *ptr; } }; template <class I> typename I::value_type //上面这一行告诉编译器这个型别,不然func无法返回 func(I ite) { return *ite; } int main(int argc, const char *argv[]) { MyIter<int> ite(new int(8)); cout << func(ite) << endl; //8 return 0; } ~
这里的func函数就可以成功的把value_type萃取出来。
但是这里还有一个隐蔽的陷阱。
就是当我们这个迭代器是一个原生的指针时就会有问题,因为原生的指针并没有内嵌型别。
这就需要这个模板针对这个类型写一个偏特化的版本。
1 #include <iostream> 2 using namespace std; 3 4 template <class T> 5 struct MyIter{ 6 typedef T value_type; 7 //声明内嵌型别为value_type 8 T* ptr; 9 MyIter(T* p = 0):ptr(p){ } 10 T& operator*()const{ return *ptr; } 11 }; 12 13 template <class I> 14 struct iterator_traits_1{ 15 typedef typename I::value_type value_type; 16 }; 17 //对MyIter进行封装,获取它的内嵌型别 18 19 template <class T> 20 struct iterator_traits_1<T*>{ 21 typedef T value_type; 22 }; 23 //对原生指针进行型别的定义 24 25 template <class I> 26 typename iterator_traits_1<I>::value_type 27 //告诉编译器下面函数返回的型别 28 func(I ite) 29 { return *ite; } 30 31 int main(int argc, const char *argv[]) 32 { 33 MyIter<int> ite(new int(8)); 34 cout << func(ite) << endl; 35 //返回8 36 int a = 5; 37 int *b = &a; 38 cout << func(b) << endl; 39 //返回5 40 return 0; 41 }
这里我们对原来的类型MyIter又多了一层封装,这样的好处呢就是可以让下面的函数对原生指针也可以使用。
为了可以使用原生指针,我们又写了一个偏特化的版本。
特化版本和偏特化的版本的区别是,特化版本只是针对某一特定的类型实现。
而偏特化版本是对于一组特定的类型特化,更具一般性。
这里我们是针对所有的原生指针生成一个偏特化版本。
- 关于traits
traits在这里的作用是非常重要的,它所扮演的角色不仅仅是对各个类型的兼容,而且也是一个“类型萃取机”。
需要说明的一点就是要想兼容traits,必须有相关的内嵌型别定义;这一点在STL的迭代器中至关重要。
- iterator部分源码重列
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
1 //STL全部迭代器类型 2 struct input_iterator_tag {}; 3 struct output_iterator_tag {}; 4 struct forward_iterator_tag {} : public input_iterator_tag {}; 5 struct bidirectional_iterator_tag : public forward_iterator_tag {}; 6 struct random_access_iterator_tag : public bidirectional_iterator_tag {}; 7 8 template <class Category, class T, class Distance = ptrdiff_t, class Pointer = T*, class Reference = T&> 9 struct iterator{ 10 typedef Category iterator_category; 11 typedef T value_type; 12 typedef Distance difference_type; 13 typedef Pointer pointer; 14 typedef Reference reference; 15 }; 16 17 //类型萃取机traits 18 template <class Iterator> 19 struct iterator_traits{ 20 typedef typename Iterator::iterator_category iterator_category; 21 typedef typename Iterator::value_type value_type; 22 typedef typename Iterator::difference_type defference_type; 23 typedef typename Iterator::pointer pointer; 24 typedef typename Iterator::reference reference; 25 }; 26 27 //针对原生指针的偏特化版本 28 template <class T> 29 struct iterator_traits<T*>{ 30 typedef random_access_iterator_tag iterator_category; 31 typedef T value_type; 32 typedef ptrdiff_t difference_type; 33 typedef T* pointer; 34 typedef T& reference; 35 }; 36 37 //这个函数可以很方便的决定某个迭代器的类型(category) 38 template <class Iterator> 39 inline typename iterator_traits<Iterator>::iterator_category 40 iterator_category(const Iterator&) 41 { 42 typedef typename iterator_traits<Iterator>::iterator_category category; 43 return category(); 44 } 45 46 //这个函数可以很方便的决定某个迭代器的distance_type 47 template <class Iterator> 48 inline typename iterator_traits<Iterator>::difference_type* 49 distance_type(const Iterator&) 50 { 51 return static_cast<typename iterator_traits<Iterator>::difference_type*>(0); 52 } 53 54 //这个函数可以很方便的决定某个迭代器的value_type 55 template <class Iterator> 56 inline typename iterator_traits<Iterator>::value_type* 57 value_type(const Iterator&) 58 { 59 return static_cast<typename iterator_traits<Iterator>::value_type*>(0); 60 } 61 62 //以下是整组的distance函数 63 //两个__distance函数中的第三个参数没有实际意义,仅仅是为了判别迭 64 //代器类型 65 template <class InputIterator> 66 inline iterator_traits<InputIterator>::difference_type 67 __distance(InputIterator first, InputIterator last, input_iterator_tag){ 68 iterator_traits<InputIterator>::difference_type n = 0; 69 while(frist != last){ 70 ++first; ++n; 71 } 72 return n; 73 } 74 template <class RandomAccessIterator> 75 inline iterator_traits<RandomAccessIterator>::difference_type 76 __distance(RandomAccessIterator first, RandomAccessIteratorIterator last, 77 random_access_iterator_tag){ 78 return last - first; 79 } 80 81 template <class InputIterator> 82 inline iterator_traits<InputIterator>::difference_type 83 distance(InputIterator first, InputIterator last) 84 { 85 typedef typename 86 iterator_traits<InputIterator>::iterator_category category; 87 return __distance(first, last, category()); 88 }
关于这些特性,在STL大量的使用,一定程度上补充了c++的不足;
最重要的是这些特性帮助我们在程序编译时就完成了类型的判断,而不是自己写个函数在运行时判断,这样做
更快,更高效。