C++ 全栈知识体系C++ 全栈知识体系
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
  • 编程语言与技术

    • Effective C++: 改善程序与设计的55个具体做法

      • 第2章 - 构造/析构/赋值运算(一)
      • 第2章 - 构造/析构/赋值运算(二)
      • 第2章 - 构造/析构/赋值运算(三)
      • 第3章 - 资源管理
      • 第4章 - 设计与声明(一)
      • 第4章 - 设计与声明(二)
      • 第5章 - 实现(一)
      • 第5章 - 实现(二)
      • 第6章 - 继承与面向对象设计
      • 第7章 - 模板与泛型编程
    • 深度探索C++对象模型

      • 第1章 - 关于对象
      • 第2章 - 构造函数语意学
      • 第3章 - Data 语意学
    • STL源码剖析

      • 第1章 - STL概论和版本简介
      • 第2章 - 空间配置器
      • 第3章 - 迭代器(iterators)概念与traits编程技法(一)
      • 第3章 - 迭代器(iterators)概念与traits编程技法(二)
      • 第4章 - 序列式容器 vector
      • 第4章 - 序列式容器 list
      • 第4章 - 序列式容器 deque
      • 第4章 - 序列式容器 stack和queue
      • 第4章 - 序列式容器 heap
      • 第4章 - 序列式容器 priority_queue
      • 第4章 - 序列式容器 slist
      • 第5章 - 关联式容器 RB-tree
      • 第5章 - 关联式容器 set和map
      • 第5章 - 关联式容器 hashtable
      • 第6章 - 算法
      • 第6章 - 算法之set
      • 第7章 - 仿函数
      • 第8章 - 配接器
  • 系统与架构

    • 深入理解计算机系统

      • 第1章 - 计算机系统漫游
      • 第2章 - 信息的表示和处理
      • 第3章 - 程序的机器级表示
      • 第5章 - 优化程序性能
      • 第6章 - 存储器层次结构
      • 第7章 - 链接
      • 第8章 - 异常控制流
      • 第9章 - 虚拟内存
      • 第10章 - 系统级I/O
      • 第11章 - 网络编程
      • 第12章 - 并发编程
    • 大型网站技术架构——核心原理与案例分析

      • 第1章 - 大型网站架构演化
      • 第2章 - 大型网站架构模式
      • 第3章 - 大型网站核心架构要素
      • 第4章 - 瞬时响应:网站的高性能架构
      • 第5章 - 万无一失:网站的高可用架构
      • 第6章 - 永无止境:网站的伸缩性架构
      • 第7章 - 随需应变:网站的可扩展架构
      • 第8章 - 固若金汤:网站的安全架构
    • 从零开始学架构

      • 架构基础
      • 架构设计原则
      • 高性能架构
      • 高可用架构
    • 程序员的自我修养————链接、装载与库

      • 第1章 - 简介
      • 第2章 - 静态链路
      • 第3章 - 目标文件里有什么
      • 第4章 - 静态链接
      • 第7章 - 动态链接
      • 第8章 - 共享库版本
      • 第10章 - 内存
      • 第11章 - 运行库
      • 第12章 - 系统调用与API
      • 第13章 - 运行库实现
  • 软件开发实践

    • 重构改善既有代码的设计

      • 第1章 - 重构,第一个示例
      • 第2章 - 重构的原则
      • 第3章 - 代码的坏味道
      • 第5章 - 重构列表
      • 第6章 - 重新组织函数
      • 第7章 - 在对象之间搬移特性
      • 第8章 - 重新组织数据
      • 第9章 - 简化条件表达式
      • 第10章 - 简化函数调用
      • 第11章 - 处理概括关系
      • 第12章 - 设计之大型重构
    • 代码大全2

      • 第1章 - 欢迎进入软件构建的世界
      • 第2章 - 用隐喻来更充分地理解软件开发
      • 第3章 - 三思而后行: 前期准备
      • 第4章 - 关键的构建决策
      • 第5章 - 软件构建中的设计
    • Linux多线程服务端编程——使用muduo C++ 网络库

      • Buffer类的设计
      • 设计与实现
      • 定时器与TimerQueue
      • Protobuf网络传输和Protobuf编解码器与消息分发器
      • EventLoop类剖析
      • EventLoopThread和EventLoopThreadPool剖析
      • TCP网络库和核心类
      • Connector剖析
      • TcpClient剖析
      • 学习总结
      • timing wheel
      • 消息广播服务
      • 线程安全的对象生命期管理
  • 数据处理与应用设计

    • 数据密集型应用系统设计

      • 第1章 - 可靠、可扩展与可维护的应用系统
      • 第2章 - 数据模型与查询语言
      • 第3章 - 数据存储与检索
      • 第4章 - 数据编码与演化
      • 第5章 - 数据复制
      • 第6章 - 数据分区
      • 第7章 - 事务

第3章:迭代器(iterators)概念与traits编程技法(一)

  • 利用function template的参数推导机制
  • 声明内嵌型法
  • 模板偏特化

迭代器概述

Iterator是一种抽象的设计概念《Design Patterns》其中对于iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所包含的各个元素,而又无需暴露该聚合物的内部表达方式。

STL的中心思想在于:将数据容器(containers)和算法(algorithms)分开彼此独立设计,最后再以一贴粘合剂将其撮合。这个粘合剂就是Iterator。迭代器是一种类似指针的对象,最重要的便是对operator *和operator->进行重载,为了让迭代器适用于任何型态的结点,需要把它设计为class template。以算法的find函数为例,它接受两个迭代器和一个“查找目标”:

template <class InputIter, class T>
inline InputIter find(InputIter first, InputIter last,
                       const T& val)
{
  while (first != last && !(*first == val))
    ++first;
  return first;
}

只要给予不同的迭代器,find()函数便能对不同的容器进行查找操作:

#include <vector>
#include <list>
#include <deque>
#include <algorithm>
#include <iostream>
using namespace std;

// 迭代器是一种行为类似指针的对象,对operator*和operator->进行重载

int main() {
    const int arraySize = 7;
    int ia[arraySize] = {0, 1, 2, 3, 4, 5, 6};

    vector<int> ivect(ia, ia + arraySize);
    list<int> ilist(ia, ia + arraySize);
    deque<int> ideque(ia, ia + arraySize);

    vector<int>::iterator it1 = find(ivect.begin(), ivect.end(), 4);
    if (it1==ivect.end())
        cout << "4 not found." << endl;
    else
        cout << "4 found. " << *it1 << endl;

    list<int>::iterator it2 = find(ilist.begin(), ilist.end(), 6);
    if (it2==ilist.end())
        cout << "6 not found." << endl;
    else
        cout << "6 found. " << *it2 << endl;

    deque<int>::iterator it3 = find(ideque.begin(), ideque.end(), 8);
    if (it3==ideque.end())
        cout << "8 not found." << endl;
    else
        cout << "8 found. " << *it3 << endl;
	
	return 0;
}

执行结果:

[root@192 3_STL_iterator]# ./3_1_find
4 found. 4
6 found. 6
8 not found.

在算法中运用迭代器,很可能会用到其相应型别,而C++之支持sizeof( ),并未支持typeof(),即便动用RTTI性质中的typeid( ),获得的也只是型别的别名,不能用来当变量声明用。

解救的办法有几个:

利用function template的参数推导机制

 template <class I, class T>
  void func_impl(I iter, T t) {
          T tmp; // 这里就是迭代器所指物的类型新建的对象
          // ... 功能实现
  }
  ​
  template <class I>
  inline
  void func(I iter) {
          func_impl(iter, *iter); // 传入iter和iter所指的值,class自动推导
  }
  ​
  int main() {
      int i;
      func(&i);
  }

我们以func()对外接口,却把实际操作全部置于func_imp1()之中。由于func_imp1()是一个function template,一旦被调用,编译器会自动进行template参数推导。于是导出型别T,顺利解决问题。但是,template参数推导机制推导的只是参数,无法推导返回值型别,所以如果迭代器所指对象的型别必须用于函数的传回值时,只能采用声明内嵌型别的方法。

声明内嵌型法

 template <class T>
  struct MyIter {
      typedef T value_type; // 内嵌型别声明
      // ...
  };
  ​
  template <class I>
  typename I::value_type //这一行是func的回返值型别,typename告诉编译器I::value_type是一个型别
  func(I ite) {
      return *ite;
  }
  ​
  // ...
  MyIter<int> ite(new int(8));
  cout << func(ite);

看起来似乎解决了问题,但是忽略了一个问题,并不是所有迭代器都是class type,原生指针就不是。如果不是class type,就无法定义它内嵌型别。但STL绝对必须接受原生指针作为一种迭代器。进一步引入(template partial specialization)模板偏特化的概念。

模板偏特化

Partial Specialization (偏特化)意义:如果class template拥有一个以上的template参数,我们可以针对其中某个(或数个,但非全部)template参数进行特化工作。换句话说,我们可以在泛化设计中提供一个特化版本(也就是将泛化版本中的某些template参数赋予明确的指定)。

《泛型思维》对Partial Specialization 定义:针对(任何)template参数更进一步的条件限制所设计出来的一个特化版本。由此,面对以下这么一个class template:

template<typename T>
class C {……};  //这个泛化版本允许(接受)T为任何型别
  ​
//我们更容易接受它有一个形如下的Partial Specialization 
template<typename T>
class C<T*> {……};  //这个泛化版本仅适用于"T为原生指针"的情况,便是"T为任何型别"的一个更进一步的条件限制
template <class I>
struct iterator_traits {
      typedef typename I::value_type value_type;
};
  ​
template <class I>
struct iterator_traits<T*> {
      typedef T value_type;
};
  ​
template <class I> typename iterator_traits<I>::value_type
func(I ite) {
      return *ite;
}

func在调用 I 的时候,首先把 I 传到萃取器中,然后萃取器就匹配最适合的 value_type。(萃取器会先匹配最特别的版本)这样当你传进一个原生指针的时候,首先匹配的是带<T*>的偏特化版本,这样 value_type 就是 T,而不是没有事先声明的I::value_type。这样返回值就可以使用typename iterator_traits<I>::value_type来知道返回类型。如下是STL源码剖析里的traits所扮演的特性萃取机图。

traits特性萃取机

如图说明了traits所扮演的“特性萃取机”角色,萃取各个迭代器的特性,这里所谓的迭代器特性,指的是迭代器的相应型别。最常见的迭代器型别有5种value_type、difference_type、pointer、reference、iterator_category,因此traits中会有这5个类型。

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

iterator_traits 必须针对传入之型别为pointer及pointer-to-const者,设计特化版本。

​

Last Updated:
Contributors: klc407073648
Prev
第2章 - 空间配置器
Next
第3章 - 迭代器(iterators)概念与traits编程技法(二)