zoukankan      html  css  js  c++  java
  • std::iterator 与 std::iterator_traits

    std::iterator

    std::iterator 是一个模板类,其声明为:

    template< 
        class Category,
        class T,
        class Distance = std::ptrdiff_t,
        class Pointer = T*,
        class Reference = T& 
    > struct iterator;
    

    std::iterator 是为简化迭代器所需类型的定义而提供的基类。也就是说当我们写一个模板类时,需要定义自己的迭代器 iterator,那么我们可以将 std::iterator 作为自定义迭代器的基类。
    std::iterator 的模板参数:

    • Category: 类型为 iterator_category,表示迭代器的种类,共有5类:
    • T :类型为 value_type, 可以通过解除引用迭代器获得的值的类型。 对于输出迭代器,此类型应为 void
    • Distance: 类型为 difference_type, 一种可用于标识迭代器之间距离的类型。即两个迭代器相减(若支持的话)的结果类型。
    • Pointer: 类型为 pointer,定义指向迭代类型的指针(T)。即指向 T 类型的指针。
    • Reference: 类型为 reference,定义迭代类型的引用(T)。即 T 的引用类型。
      例如自定义一个继承自 std::iterator 的迭代器:
    #include <algorithm>
    #include <iterator>
    using namespace std;
    
    template<long FROM, long TO>
    class Range
    {
    public:
    	class Longiterator : public std::iterator<std::input_iterator_tag,  //@ iterator_category
    		long, //@ value_type
    		long, //@ difference_type
    		const long*, //@ pointer
    		long> //@ reference
    	{
    		long num_ = FROM;
    	public:
    		explicit Longiterator(long num = 0) : num_(num) {}
    		Longiterator& operator++() { num_ = TO > FROM ? num_ + 1 : num_ - 1; return *this; }
    		Longiterator operator++(int) { Longiterator retval = *this; ++(*this); return retval; }
    		bool operator==(Longiterator other)const { return num_ == other.num_; }
    		bool operator!=(Longiterator other)const { return !(*this == other); }
    		reference operator*()const { return num_; }
    	};
    
    	Longiterator begin() { return Longiterator(FROM); }
    	Longiterator end() { return Longiterator(TO > FROM ? TO + 1 : TO - 1); }
    };
    
    int main()
    {
    	auto range = Range<2, 10>();
    	auto iter = std::find(range.begin(),range.end(),8);
    	cout << *iter << endl;
    
    	//@ range_based for 
    	for (const auto& elem : range)
    		cout << elem << " ";
    	cout << endl;
    
    	return 0;
    }
    

    std::iterator_traits

    STL 中的算法与容器之间是通过迭代器架起的桥梁,算法需要知道迭代器的信息,以便采用最优算法。但是算法如何知道迭代器的详细信息呢,此时就需要一个中间层:iterator_traits,它也是一个模板类,将 iteratoe进行了包装,并使用模板局部特化技术:

    //使用iterator提供的信息
    template<typename Iterator>
    struct iterator_traits
    {
      typedef typename Iterator::iterator_category iterator_category;
      typedef typename Iterator::value_type        value_typep;
      typedef typename Iterator::difference_type   difference_type;
      typedef typename Iterator::pointer           pointer;
      typedef typename Iterator::reference         reference;
    };
    
    //@ 局部特化,c++内置指针。
    template<typename T>
    struct iterator_traits<T *>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef T                          value_type;
      typedef ptrdiff_t                  difference_type;
      typedef T*                         pointer;
      typedef T&                         reference;
    };
    
    //@ 局部特化,const c++内置指针。
    template<typename T>
    struct iterator_traits<const T *>
    {
      typedef random_access_iterator_tag iterator_category;
      typedef T                          value_type; //@ 注意这里不是const T;如果是const T,算法拿到这个类型,用这个类型定义变量后,却无法改变其值,那就没有作用了,所以是T。
      typedef ptrdiff_t                  difference_type;
      typedef const T*                   pointer;
      typedef const T&                   reference;
    };
    

    例如:list类的size方法。

    size_type size() const {
      size_type result = 0;
      distance(begin(), end(), result);
      return result;
      //return distance(begin(), end());    
    }
    
    struct input_iterator_tag {};
    struct output_iterator_tag {};
    struct forward_iterator_tag : public input_iterator_tag {};
    struct bidirectional_iterator_tag : public forward_iterator_tag {};
    struct random_access_iterator_tag : public bidirectional_iterator_tag {};
    
    template <class InputIterator, class Distance>
    inline void __distance(InputIterator first, InputIterator last, Distance& n, 
                           input_iterator_tag)
    {
      while (first != last) { ++first; ++n; }
    }
    
    template <class RandomAccessIterator, class Distance>
    inline void __distance(RandomAccessIterator first, RandomAccessIterator last, 
                           Distance& n, random_access_iterator_tag)
    {
      n += last - first;
    }
    
    template <class Iterator>
    inline typename iterator_traits<Iterator>::iterator_category
    iterator_category(const Iterator&) {
      typedef typename iterator_traits<Iterator>::iterator_category category;      //@ 1
      return category();
    }
    
    template <class InputIterator, class Distance>
    inline void distance(InputIterator first, InputIterator last, Distance& n)
    {
      __distance(first, last, n, iterator_category(first));
    }
    

    代码1处,算法向 iterator_traitsiterator_category 的信息,如果 iterator 能提供,就使用 iterator 里的 iterator_category,如果 iterator 不能提供,就使用 iterator_traits 里的 iterator_category。得到iterator_category 后,就可以在编译阶段确定调用哪一个 __distance 方法了。

  • 相关阅读:
    ASIHTTPRequest系列(一):同步和异步请求
    浅谈SQL Server2005的几种分页方法
    在iphone越狱机器中使用Hook
    iphone4 双击Home键 截获
    xcode中打印毫秒时间
    获得一个不错的电子书翻页效果,和大家分享
    【转】iOS平台XML解析类库对比和安装说明
    xml的sax解析方法
    svn 日常使用技巧以及vim profile的配置
    自制固件iOS4.1刷机、解锁教程
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/13463634.html
Copyright © 2011-2022 走看看