前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++学习笔记-迭代器(iterator)与萃取机(traits)

C++学习笔记-迭代器(iterator)与萃取机(traits)

原创
作者头像
买唯送忧
修改2021-05-21 18:18:05
1.7K0
修改2021-05-21 18:18:05
举报

一、迭代器的设计思维

1、迭代器的定义

提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露容器的内部表述方式。stl的中心思想就是容器和算法分离,然后用一个胶着剂将它们撮合在一起。下面展示一下应用:比如算法find(),要寻找各种容器里的数据,代码如下:

void test_find(){
    const int arraySize = 10;
    int num[arraySize] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vector <int> vec(num, num + arraySize);
    vector <int> ::iterator it1 = find(vec.begin(), vec.end(), 8);
    if (it1 == vec.end()){
        cout << "not found" << endl;
    }else{
        cout << "found it :" << *it1 << endl;
    }

    list <int> lis(num, num + arraySize);
    list <int>::iterator it2 = find (lis.begin(), lis.end(), 4);
    if (it1 == vec.end()){
        cout << "not found" << endl;
    }else{
        cout << "found it :" << *it2 << endl;
    }

    deque <int> deq(num, num + arraySize);
    deque <int>::iterator it3 = find (deq.begin(), deq.end(), 5);
    if (it3 == deq.end()){
        cout << "not found" << endl;
    }else{
        cout << "found it :" << *it3 << endl;
    }
}

从上面的代码可以看出,只要给出不同的迭代器,find()就会对不同的容器进行查找操作。

2、迭代器是一种智能指针

迭代器是一种类似于指针的对象,而又不同于普通的原生指针,它能够让各种对象看上去像指针一样操作,,不仅仅是基本类型;众所周知,指针最常用的操作就是取值和成员访问:也就是说迭代器作为一种智能指针,需要对operator*和operator->进行重载工作,这里放一段标准库里的auto_ptr的程序,可以更好的理解智能指针:

template <class T>
class auto_ptr{
public:
    explicit auto_ptr(T *p = 0) : pointee(p){} //普通构造函数
    template <class U>
    auto_ptr(auto_ptr<U>& rhs) : pointee(rhs){} //拷贝构造
    template <class U>
    auto_ptr& operator= (auto_ptr<U>& rhs){
        if (this != &rhs) reset(rhs.release);
        return *this;
    }
    ~auto_ptr() {delete pointee;}
    //最关键的两个
    T& operator*() const {return *pointee;}
    T* operator->() const {return pointee;}
private:
    T* pointee;
};



//调用
auto_ptr<string> ps (new string("ss"));
cout << *ps << endl; //输出ss;
//string可以换成自己的自定义类;

因此完全可以自己按照auto_ptr写一个迭代器,再加上自己需要的功能,比如指针自增(重载operator++)等,比如:

ListIter <ListItem<int>> begin(mylist.front());
//ListIter是迭代器类,,ListItem<int>是一个单向链表类,mylist是直接定义的一个基于单链表的容器
//这样说明,begin就是指向自定义容器第一个位置的指针,是不是类似于:vector<int>::iterator ite = vec.begin();

3、迭代器相应类别

既然迭代器要把两个独立的部件算法和容器撮合在一起,那么相应的类别必须得一样;当然,编译器是自带参数推导的,就比如函数模板,它是会自己推导出传递的是什么类型,但是返回值没办法推导呀,这个也可以解决,使用内嵌声明就行了:

template <class T>
struct MyIter{
    typedef T value_type; 内嵌类型
    T* ptr;
    MyIter(T* p = 0): ptr(p){}
    T& operator*()const {return *ptr;}
};


template <class I>
typename I::value_type  //这一行都是func的返回类型(因为I是一个template参数,在编译器具现之前,编译器对I一无所知,使用typename可以告诉编译器这是一个类型
func(I ite){
    return *ite;
}

但是指针不能内嵌类型,如果迭代器是一个原生指针不就无法内嵌吗?这里就不得不说一个模板偏特化了。

(1)模板偏特化

模板偏特化分为两种:一种是个数上的特化,一种是类型上的特化:

//个数上的特化
//比如泛化模板如:
template<class T, class U, class V>//这是一种泛化
//个数上的特化就是让一个值有默认值,比如:
template<class T, class U, class V == string>

//类型上的特化
//比如一个模板
template <class T>
class Demo <T*>{}//这就是类型上的特化,只接受原生指针;

回到之前的问题;算法和容器两个独立的部件靠迭代器撮合一起的,那必须对应的类型要一样,就好比是这样一个场景:算法问迭代器,你作为我算法的参数,你指向的对象的数据类型是什么,到时候返回值别错了。你知道吗? 迭代器如果说不知道,,那就类型不对就无法进行下去了,如果说知道,那算法就直接说,那好,我要对你指向的容器进行操作了,这样操作自然而然的就通顺了,,那迭代器是怎么回答算法这个问题的呢?这就得看看萃取机了。

二、萃取机

这里就直接把对应的代码贴出来

// 用于traits出迭代其所指对象的型别
template <class Iterator>那
struct iterator_traits
{
  // 迭代器类型, STL提供五种迭代器
  typedef typename Iterator::iterator_category iterator_category;

  // 迭代器所指对象的型别
  // 如果想与STL算法兼容, 那么在类内需要提供value_type定义
  typedef typename Iterator::value_type        value_type;

  // 这个是用于处理两个迭代器间距离的类型
  typedef typename Iterator::difference_type   difference_type;

  // 直接指向对象的原生指针类型
  typedef typename Iterator::pointer           pointer;

  // 这个是对象的引用类型
  typedef typename Iterator::reference         reference;
};
// 针对指针提供特化版本
template <class 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;
};

// 针对指向常对象的指针提供特化
template <class T>
struct iterator_traits<const T*>
{
  typedef random_access_iterator_tag iterator_category;
  typedef T                          value_type;
  typedef ptrdiff_t                  difference_type;
  typedef const T*                   pointer;
  typedef const T&                   reference;
};

那萃取机怎么告诉迭代器有没有这个类型呢?

这里直接来个代码比较好理解:

template <class T, class V>
typename iterator_traits<I>::difference_type //返回值
count(T first, I last, const T& value){
    //统计容器里value的个数
    typename iterator_traits<I>::difference_type n = 0; 
    //这里就是回答,因为迭代器I可以通过萃取机萃取出需要的difference_type,如果通过::出不来类型,那就是回答不了。
    ...
    return n;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、迭代器的设计思维
    • 1、迭代器的定义
      • 2、迭代器是一种智能指针
        • 3、迭代器相应类别
          • (1)模板偏特化
      • 二、萃取机
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档