STL 之 iterator traits 备忘

//5种迭代器,为了激活重载机制,定义的5个类型。每种迭代器就是一个类型。

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{};

为了定义自己的迭代器,可以继承自下面的iterator类,避免迭代器型别的未定义。

//Base class for iterator class
template <class Category, class T, class Distance=ptrdiff_t, class Pointer = T*, class Reference =T&>
struct iterator
{
    typedef Category iterator_category;
    typedef T value_type;
    typedef Distance difference_type;
    typedef Pointer pointer;
    typedef Reference reference;
};

iterator_traits类,就是一些typedef,相当于就是将迭代器的最本质的类型忠实的呈现出来。这里值得注意的是,要使得这个迭代器忠实的完成这项工作,那么各个迭代器的定义就必须定义相应的5个性别。value_type difference_type  iterator_category pointer reference .

template<class Iterator>
struct iterator_traits
{
    typedef typename Iterator::category iterator_category;
    typedef typename Iterator::value_type value_type;
    typedef typename Iterator::difference_type difference_type;
    typedef typename Iterator::pointer pointer;
    typedef typename Iterator::reference reference;
};

然而这对于指针而言是不可行的,因为指针没有结构体,我们无法在其中定义这5个型别,于是针对指针,我们定义了iterator_traits的特化版本。

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 Iterator>
inline typename iterator_traits<Iterator>::iterator_category
iterator_category(const Iterator&)
{
  typedef typename iterator_traits<Iterator>::iterator_category category;
  return category(); //random_access_iterator_tag or bidirectional_iterator_tag ...
}

//pointer to the difference_type
template< class Iterator>
inline typename iterator_traits<Iterator>::difference_type*
distance_type (const Iterator &)
{
  return static_cast<typename iterator_traits<Iterator>::difference_type *>(0);
}

template< class Iterator>
inline typename iterator_traits<Iterator>::value_type *
distance_type (const Iterator &)
{
  return static_cast<typename iterator_traits<Iterator>::value_type* > (0);
}

distance函数在上述traits下的实现代码:

//distance function

template<class InputIterator>
inline iterator_traits<InputIterator>::difference_type
__distance(InputIterator first, InputIterator last, input_iterator_tag)
{
  iterator_traits<InputIterator>::difference_type n=0;
  while(first != last)
  {
      ++first;++n;
  }
  return n;
}
template<class RandomIterator>
inline typename iterator_traits<RandomIterator>::difference_type
__distance(RandomIterator first, RandomIterator last, random_access_iterator_tag)
{
    return last-first;
}

//user
template<class InputIterator>
inline iterator_traits<InputIterator>::difference_type
distance(InputIterator first, InputIterator last)
{
    typedef typename iterator_traits<InputIterator>::iterator_category category;
    return __distance(first,last,category());//category()构造一个临时对象,进行参数推导,决定重载函数。
}

参考:STL源码剖析

STL 之 iterator traits 备忘

时间: 2024-08-07 05:26:37

STL 之 iterator traits 备忘的相关文章

STL中的Traits编程技法

最近在看读<STL源码剖析>,看到Traits编程技法这节时,不禁感慨STL源码作者的创新能力.那么什么是Traits编程技法呢?且听我娓娓道来: 我们知道容器的许多操作都是通过迭代器展开的.其中容器类似于数组,迭代器类似于指针.我们用数组来写个例子: 1 int arr[5] = {1,2,3,4,5}; 2 int *p; 3 p = &arr[2]; 假设,我将第1.2遮挡起来,问你p所指向的对象arr[2]是什么类型,你恐怕无法回答.因为它可以是int,char,float甚至

C++备忘

从<C++标准库>里面看到的一些技巧,以及自己遇到的一些技巧,备忘. 从流中读取数据存入容器 1 copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(vInput));//从cin中读取string 类型的数据存入 vInput 这个vector 更多迭代器:http://www.cnblogs.com/L-hq815/archive/2012/08/28/26607

RxJava & RxAndroid备忘

"你问我要去向何方,我指着大海的方向" 今天在刷G+的时候看到Dave Smith推荐了一个视频 <Learning RxJava (for Android) by example> 点进去看了一下,原来是位熟悉的"阿三哥",视频封面如下:(没有歧视的意思,不要喷我啊~,为什么感到熟悉?接着往下看) 几乎同时也看到了JetBrains在G+也推荐了篇在Medium上的博文 <RxAndroid And Kotlin (Part 1)> ,然后

工作备忘:cacti&nagios登录密码修改方法

[[email protected]]# mysql -u root -p mysql> use cacti; mysql> select * from user_auth; mysql> update user_auth set password=md5("cactipasswd") where id='1'; 现在cacti登录的新密码就是cactipasswd [[email protected]]# /usr/bin/htpasswd /usr/local/n

备忘-linux文件系统结构

用apache的时候总是要进入/var/www, 用久了开始好奇这些个目录都是派什么用处的,简单整理了一下 /bin 存放二进制命令文件,这个目录下面不允许存在子目录/boot bootloader的静态文件,当然OS的文件也必须在这里/dev 设备文件,MAKEDEV命令可以创建设备/etc 特定主机的配置文件,必须是静态文件,非可执行文件: opt, X11, sgml, xml/home 用户目录 /lib 存放主要的共享库和核心模块/media 可移除媒体的挂载点: floppy, cd

[转]Windows环境下尝试安装并配置PHP PEAR备忘

转自:http://wangye.org/blog/archives/266/ 什么是PEAR 来自百度百科:PEAR 是PHP扩展与应用库(the PHP Extension and Application Repository)的缩写.它是一个PHP扩展及应用的一个代码仓库,简单地说,PEAR之于PHP就像是CPAN(Comprehensive Perl Archive Network)之于Perl. 由此可见PEAR是PHP代码的仓库,在这里可以找到很多有用的代码,避免我们重复写一些功能,

Table view 备忘

Table view 备忘 本篇会以备忘为主,主要是一些基础的代理方法和数据源方法具体的优化好点子会后续跟上. Table view的数据源方法 必须实现的数据源方法 // 返回每一行的cell,可以做缓存处理,同样也可能会造成复用问题. func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // tableview 和 cell 都是在s

oracle下 启动subversion命令 及 oracle相关服务启动备忘

linux shell下  svnserve - d -r + 目录   例如:svnserve -d -r /svn 启动 svn服务. 访问svn://192.168.0.120/kjcg 测试. 启动oracle: 一.如何启动数据库实例 1.进入到sqlplus启动实例 [[email protected] ~]$ su - oracle --“切换到oracle用户” 2. Password: [[email protected] ~]$ lsnrctl start  --“打开监听”

linux下常用命令备忘

转自:Linux 命令集锦 linux下查看监听端口对应的进程 # lsof -i:9000 # lsof -Pnl +M -i4 如果退格键变成了:"^h". 终端连接unix删除退格键,按住CTL键同时按delete Linux搜索 # find / -name "xxx.conf" 查看linux是32位还是64位的命令 #file /sbin/init #getconf LONG_BIT #getconf -a 在Linux和Windows下都可以用nslo