1.STL的迭代器类型标识,和容器中的迭代器类型。

2.使用trait技术实现stl的advance功能。

3.迭代器trait中的其他类型定义。

1.STL的迭代器类型标识,和容器中的迭代器类型。

熟悉的迭代器类型,输入、输出、前向、双向、随机。

c++标准程序库分别提供专属的卷标结构(tag struct),一个空的结构体来标志具体是哪种类型迭代器。如下:

        //    ITERATOR STUFF (from <iterator>)// ITERATOR TAGS (from <iterator>)
struct input_iterator_tag{    // identifying tag for input iterators
    };struct output_iterator_tag{    // identifying tag for output iterators
    };struct forward_iterator_tag: input_iterator_tag, output_iterator_tag{    // identifying tag for forward iterators  这些继承关系有有效的IS-A
    };struct bidirectional_iterator_tag: forward_iterator_tag{    // identifying tag for bidirectional iterators
    };struct random_access_iterator_tag: bidirectional_iterator_tag{    // identifying tag for random-access iterators};

而在每个容器中,就使用上述的tag struct标识自自身迭代器的类型,大概的思路是下面的样子,但真正源码实现复杂多。

// vector 容器 随机迭代器。list 容器 双向迭代器。template<...>
class vector{
public: class iterator{ public: typedef random_access_iterator_tag iterator_category;       // 类型定义: vector<T>::iterator::iterator_category 就是 random_access_iterator_tag     // 即类型里面还有一个类型, 而这个类型仅仅是用来标识 这个类是属于哪个类型的。 };
};template<...>
class list{
public: class iterator{ public: typedef bidirectional_iterator_tag iterator_category; };
};

2.使用trait技术实现stl的advance功能。

STL标准模版库={容器templates,迭代器templates(关联容器 和 算法),算法templates,工具性template如advance}。这里选择迭代器模版和Advance的实现来讲解trait技术。

先看看advance的用法:

// advance 函数签名std::advance
template <class Iterator, class Distance>void advance (Iterator& it, Distance n);

// advance example
#include <iostream>     // std::cout
#include <iterator>     // std::advance
#include <list>         // std::listint main () {std::list<int> mylist;for (int i=0; i<10; i++) mylist.push_back (i*10);std::list<int>::iterator it = mylist.begin();std::advance (it,5); std::cout << "The sixth element in mylist is: " << *it << '\n';return 0;
}

advance内部操作时候,需要知道advance的迭代器类型,看有哪些可用操作,比如随机访问器可以直接+= -=操作,前向仅支持++,输入输出均不支持,例子中的list属于双向,支持++,--。

所以在advance内部需要在取得某种类型信息,即迭代器的类型,进行不同的实现。

如何取得类型信息呢,在1中其实我们已经定义了迭代器的类型,可以通过 ”容器类型::iterator::iterator_category“来获取类型信息。

但如果要支持内置类型,比如指针是一种随机迭代器类型,那么类型信息就不能放在类型内了,意味着类型内的嵌套类的方式不能工作,所以类型的信息必须位于类型自身之外。

trait标准技术是把它放进一个template,并进行一个偏特化版本,来实现迭代器所属类型trait。trait特性的意思 就有有关迭代器的相关特性。

// 即再封装一层,如果是用户自定义的,就直接获取内部定义的迭代器类型
// 如果是内置类型,就直接给设定成他所属的迭代器类型,用模版偏特化
// iterator_traits
template<typename IterT>
struct iterator_traits{ typedef typename IterT::iterator_category iterator_category; // 注意: 这里typename关键字 指示编译器解析 IterT::iterator_category 为一个类型
    ...
};template<typename IterT>        //template 偏特化,针对内置指针
struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category;
};
template<typename IterT>
struct iterator_traits<const IterT*>{ typedef random_access_iterator_tag iterator_category;
};
 

在advance的用法中,就可以使用 iterator_traits 类来判断是什么类型

// advance运行时确定使用哪种迭代器类型版本template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{ if (typeid(typename std::iterator_traits<IterT>::iterator_category) == typeid(std::random_access_iterator_tag)) { iter += d;} else if(前向迭代器类型){ if (d < 0){throw std::out_of_range("Negative distance");} while (d--) ++iter; }else if(等等其他类型)...
} 

使用重载函数的机制,在编译器就确定调用哪个迭代器类型的advance,以提高运行时效率。

// advance编译器确定使用哪种迭代器类型版本
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{ doAdvance(iter, d, typename std::iterator_traits<IterT>::iterator_category());
}
// 比如 双向迭代器的函数 。重载doAdvance,实现不同的迭代器类型的具体操作。
// 可以看到迭代器类型仅仅是个重载的作用,使得重载机制得以运行,都不需要变量名。
void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag)
{                                                                                                               if (d >= 0) {while (d--) ++iter;} else {while(d++) --iter;}
} 

3.迭代器trait中的其他类型定义

template<class IterT>
struct iterator_traits{typedef typename IterT::iterator_category iterator_category;  // 迭代器的类型所属typedef typename IterT::value_type value_type;            // 迭代器所指对象的类型typedef typename IterT::difference_type difference_type;     // 迭代器之间的距离
 typedef typename IterT::pointer pointer;              // 迭代器所指内容的地址typedef typename IterT::reference reference;            // 迭代器所指之内容
};template<typename IterT>        //template 偏特化,针对内置指针
struct iterator_traits<IterT*>{ typedef random_access_iterator_tag iterator_category; typedef IterT value_type; typedef ptrdiff_t difference_type ; typedef IterT* pointer ; typedef IterT& reference ;
};

另外,STL提供了一个 iterator类,如果每个新设计的迭代器都继承他,可保证符合STL所需的规范。

// TEMPLATE CLASS iterator
template<class _Category,class _Ty,class _Diff = ptrdiff_t,class _Pointer = _Ty *,class _Reference = _Ty&>struct iterator{    // base type for iterator classes
    typedef _Category iterator_category;typedef _Ty value_type;typedef _Diff difference_type;typedef _Pointer pointer;typedef _Reference reference;};

整理自 effective C++ 条款 47:使用traits classes表现类型信息

转载于:https://www.cnblogs.com/fulina/p/7058288.html

使用traits技术表现迭代器类型 iterator_category相关推荐

  1. effective C++ 条款 47:使用traits classes表现类型信息

    stl主要由"用以表现容器.迭代器和算法"的template构成,但也覆盖若干工具性的templates,其中一个名为advance,将某个迭代器移动某个给定距离: templat ...

  2. C++ Traits技术

    要想深入的理解STL的迭代器.分配器等,就必须了解C++模板编程中的一个技巧--Traits. 1.问题的提出 C++的模板特性为泛型编程提供了支持.这样我们就可以编写更加通用的代码,而不必过分去关心 ...

  3. 【转】C++ traits技术

    [转]C++ traits技术 https://www.cnblogs.com/mangoyuan/p/6446046.html posted on 2018-08-06 19:31 时空观察者9号 ...

  4. 几种常用容器的迭代器类型

    几种常用容器的迭代器类型 容器 迭代器类型 vector 随机存取 deque 随机存取 set 双向,元素为常量 multiset 双向,元素为常量 list 双向 map 双向,key为常量 mu ...

  5. 计算机环境下的审计技术方法有哪些,审计技术方法的类型包括哪些

    所谓比较行为是指注册会计师为形成关于审计具体目标的心证而将鉴证对象信息与鉴证对象之间以及鉴证对象信息或鉴证对象与审计标准之间进行对照验证的具有批判性或怀疑性的心理活动.下面为大家介绍下2014< ...

  6. js split参数为无效字符_互联网前端开发技术JavaScript字符串类型详解

    String类型 String类型包含了三个属性和大量的可用内置方法. String对象属性 String也包含对象的通用方法,比如valueOf().toLocaleString()和toStrin ...

  7. 大数据分析技术有哪些类型

    数据分析技术使数据分析人员能够审查并回顾收集的数据,并根据信息进行推断或确定.大多数技术都侧重于应用定量技术来审查数据,一些比较常见的定量数据分析技术包括描述性统计.探索性数据分析和验证性数据分析.后 ...

  8. 高中电子技术——二极管的类型和作用

    前言:下面简单整理了二极管的种类和作用. 1. 二极管的命名方式   下面是命名的前三部分,后面的序号和规格号省略: 第一部分(电极数) 第二部分(材料和极性) 第三部分(器件类型) 数字 字母 字母 ...

  9. 三维可视化技术的多种类型

    可视化是将不可见的事物转化为可见图像的过程.三维可视化就是将最终的图像以三维的方式显示出来."三维"是一个数学概念,它表示我们生活的空间可以用三个数来描述,假设存在一个直角坐标系的 ...

最新文章

  1. Java加载词向量_W2C得到词向量之后,如何得到句子向量,
  2. SpringBoot日记——ElasticSearch全文检索
  3. 临时节点不能有child 子节点
  4. 把一个div的属性都打印出来
  5. c语言判断x的个位数是否为5,用C语言编程从键盘输入一个正整数,判断其个位数是否为5,若是5则输出“yes”,否则输出“no”...
  6. 和谐 平等_平等还是认同?
  7. 域名与网页服务器的什么对应,简述网站从域名到网页的访问流程
  8. jsp页面中出现“String cannot be resolved to a type”
  9. HBase shell执行批量脚本
  10. pandas后台导出excel_pandas导出Excel表格,银行卡号、身份证号无法正常显示的问题,该怎么解决?...
  11. 教育网系统服务器域名地址,中国教育网DNS IP地址大全(32个省)
  12. centos7 python3 爬虫登陆邮箱_使用爬虫爬取超星学习通的作业时间并且通过邮件提醒!...
  13. 根据Landset 8计算植被覆盖度
  14. Luogu P4231 三步必杀 (差分)
  15. 第一篇 香橙派刷机和开发环境准备(Armbian版)
  16. C基础学习笔记——01-C基础第02天(用户权限、VI操作、Linux服务器搭建)
  17. pycharm社区版跟专业版有什么区别
  18. Java某人再玩游戏的时候输入密码123456后成功进入游戏(输错5次则被强行退出)要求用程序实现密码验证的过程。
  19. 中地恒达振弦信号采集仪MCU采集模块
  20. Go语言 大话数据结构——图

热门文章

  1. python一些方便excel行操作的函数(一)
  2. ast.literal_eval(转)
  3. 22.敏捷估计与规划——Why Agile Planning Works笔记
  4. fiddler手机端抓包配置
  5. [LeetCode] 547. Friend Circles Java
  6. C# 依据KeyEventArgs与组合键字符串相互转换
  7. 【批处理】shift用法举例
  8. hadoop-2.7.2 分布式集群搭建
  9. Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)
  10. 关于dhtmlxScheduler的使用说明(ADD EDIT DEL,自定义CelendarBox)