c++:参数型别的推导

  STL源码剖析--侯捷

  • 总结

  尽管现在的很多语言支持参数类型的判别,但是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部分源码重列

  

 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 }                                                                                
View Code

  关于这些特性,在STL大量的使用,一定程度上补充了c++的不足;

  最重要的是这些特性帮助我们在程序编译时就完成了类型的判断,而不是自己写个函数在运行时判断,这样做

  更快,更高效。

你可能感兴趣的:(C++)