Chinaunix首页 | 论坛 | 博客
  • 博客访问: 259014
  • 博文数量: 21
  • 博客积分: 1263
  • 博客等级: 准尉
  • 技术积分: 697
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-24 00:05
个人简介

专注于Answers Ranking, Answer Monitor和log处理。

文章分类
文章存档

2014年(5)

2012年(16)

分类: C/C++

2012-04-24 15:11:02

STL源代码剖析-03 stl_construct.h中我们己经简单的讨论过type traits技术了,里面提到了对象在construct 和 destory时“它们的第三个参数__false_type和__true_type都是一个空对象,它使用的是_type_traits来提取类型特性,再根据类型特性来判断应该调用哪一个版本,对于自己写的类我们也可以特化自己的_type_traits。说白了这玩意就是问“现在使用的这个类型调用它的析构函数有用么?没屁用的话就不用调用了。”在type_traits.h中,我们可以看它type traits的定义:

  1. struct __true_type {
  2. };

  3. struct __false_type {
  4. };

  5. template <class _Tp>
  6. struct __type_traits {
  7.    typedef __true_type this_dummy_member_must_be_first;

  8.    typedef __false_type has_trivial_default_constructor;
  9.    typedef __false_type has_trivial_copy_constructor;
  10.    typedef __false_type has_trivial_assignment_operator;
  11.    typedef __false_type has_trivial_destructor;
  12.    typedef __false_type is_POD_type;
  13. };
__true_type和__false_type都是个空对象,这样不会浪费空间。用bool也能达到目地,但是bool变量不能够达到编译期绑定。__type_traits对所有的内置类型和指针都进行了特化,就好像如果我们需要复制char,那么OK,直接memcpy就OK了,但是如果不是POD类型,那么就只能一个一个构造了。当在STL里面使用我们自定义的类时,我们可以定义自己的特化__type_traits,这样就能让编译器选择比较高效的方法来操作自己的类。下面就是指针的偏特化版本:
  1. template <class _Tp>
  2. struct __type_traits<_Tp*> {
  3.    typedef __true_type has_trivial_default_constructor;
  4.    typedef __true_type has_trivial_copy_constructor;
  5.    typedef __true_type has_trivial_assignment_operator;
  6.    typedef __true_type has_trivial_destructor;
  7.    typedef __true_type is_POD_type;
  8. };
----------------------------------邪恶的分割线-----------------------------------------
在STL里面的stl_iterator_base.h头文件里,用到了iterator traits技术的有两个函数,advance和distance。前面看到type traits在constuct和destory里的使用,现在来看看advance函数:
  1. template <class _InputIter, class _Distance>
  2. inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
  3.   while (__n--) ++__i;
  4. }

  5. template <class _BidirectionalIterator, class _Distance>
  6. inline void __advance(_BidirectionalIterator& __i, _Distance __n,
  7.                       bidirectional_iterator_tag) {
  8.   __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
  9.   if (__n >= 0)
  10.     while (__n--) ++__i;
  11.   else
  12.     while (__n++) --__i;
  13. }

  14. template <class _RandomAccessIterator, class _Distance>
  15. inline void __advance(_RandomAccessIterator& __i, _Distance __n,
  16.                       random_access_iterator_tag) {
  17.   __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
  18.   __i += __n;
  19. }

  20. template <class _InputIterator, class _Distance>
  21. inline void advance(_InputIterator& __i, _Distance __n) {
  22.   __STL_REQUIRES(_InputIterator, _InputIterator);
  23.   __advance(__i, __n, iterator_category(__i));
  24. }
就在上面,advance函数的第一个参数是一个引用,即"值-结果"参数。它交给__advance来执行, iterator_category(__i)就是得到迭代器的类型了,上篇文章讲的那五种类型。
  1. template <class _Tp, class _Distance>
  2. inline input_iterator_tag
  3. iterator_category(const input_iterator<_Tp, _Distance>&)
  4.   { return input_iterator_tag(); }

  5. inline output_iterator_tag iterator_category(const output_iterator&)
  6.   { return output_iterator_tag(); }

  7. template <class _Tp, class _Distance>
  8. inline forward_iterator_tag
  9. iterator_category(const forward_iterator<_Tp, _Distance>&)
  10.   { return forward_iterator_tag(); }

  11. template <class _Tp, class _Distance>
  12. inline bidirectional_iterator_tag
  13. iterator_category(const bidirectional_iterator<_Tp, _Distance>&)
  14.   { return bidirectional_iterator_tag(); }

  15. template <class _Tp, class _Distance>
  16. inline random_access_iterator_tag
  17. iterator_category(const random_access_iterator<_Tp, _Distance>&)
  18.   { return random_access_iterator_tag(); }
然后就会选择最合适的__advance来执行了。如random_access_iterator_tag可以执行类似于指针的加减法,所以要向量向后一下子就可以了,就像要访问数组a哪个元素,直接a[x]就行了,而 input_iterator_tag则不行,它只能老老实实的一步一步走,就像list一样,要访问下一个元素必需先访问过前一个元素。
traits就是个好东西啊,比起if-else好多了。神奇的技术。



阅读(3199) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~