问题

在 C++ 泛型编程中,如何知道“迭代器所指对象的类型”,以便声明临时变量呢?我们把迭代器所指对象的类型称为value type

template <class Iterator>
void func(Iterator it)
{
// 如果我想声明Iterator所指对象类型的临时变量应该怎么办呢?
// 在这里没有办法!
}

函数模板的参数推导机制

但是可以利用函数模板的参数推导机制来达到目的。

template <class Iterator>
void func(Iterator it)
{
func_impl(it, *it); // 将任务交给func_impl完成
}
template <class Iterator, class T>

void func_impl(Iterator it, T t)

{

// 现在T就是Iterator所指对象的类型

T tmp; // 达到目的

}

这种以func函数为对外接口,实际任务由func_impl函数完成的机制称为分派机制。这种机制可以实现所谓的“C++编译期间的多态”,将在下一篇文章中讲述。

编译器会自然推导出 T 的类型,但是思考有一个新的问题“value type如何用于声明返回类型”?

迭代器的value type

函数模板的参数推导机制不能推断返回值的类型!怎么办呢?那就让迭代器告诉我们吧!

当实现一个Iterator类时,必须指明自己的value type是什么,比如:

template <class T>
struct MyIterator {
typedef T value_type; // 自己指定value type是什么
.......
};

这样,在泛型编程时可以这样获取迭代器的value type

template <class Iterator>
typename Iterator::value_type // 这一行都是返回类型声明
func(Iterator it)
{
return *it;
}

iterator_traits

接下来这个iterator_traits类模板专门用来“萃取”迭代器的特性,而value type正是迭代器特性之一。

template <class Iterator>
struct iterator_traits {
typedef typename Iterator::value_type value_type;
...... // 其他更多特性
}

这个如果iterator_traits的作用是:如果Iterator本身有value type,那么就用它。

在这之后,func函数可以重新写成这样:

template <class Iterator>
typename iterator_traits<Iterator>::value_type // 这一行都是返回类型声明
func(Iterator it)
{
return *it;
}

为什么要多加一层呢?假设每个迭代器的实现者都指定了自己的value type,但并不是每个迭代器都是class,能够通过域作用符访问里面的成员,比如原生指针int*

int main()
{
int x = 888;
func(&x); // 这样是不可以的
}

偏特化

针对原生指针类型,可以使用偏特化技术,为其定制专门的版本。

template <class T>
struct iterator_traits<T*> { // 针对原生指针T*的偏特化
typedef T value_type;
...... // 其他更多特性
}
template <class T>

struct iterator_traits<const T> { // 针对原生指针const T的偏特化

typedef T value_type;

...... // 其他更多特性

}

原生指针可能还是const T*类型,为了正确推断出T而不是const T,需要为const T*偏特化一个版本。

总结

总之,iterator_traits这个类模板是一台“榨汁机”,专门“萃取”迭代器的各种特性。它能够正常工作的一个重要原因是,设计迭代器的人共同遵守一个约定:自行定义迭代器的相应类型。STL 大家庭都遵守了这个约定,不遵守这个约定就不能兼容这个大家庭。

迭代器的相应类型共有五种,完整的iterator_traits是这样的:

template <class Iterator>
struct iterator_traits {
typedef typename Iterator::value_type value_type; // 迭代器所指对象的类型
typedef typename Iterator::iterator_category iterator_category; // 迭代器的类别
typedef typename Iterator::difference_type difference_type; // 两个迭代器的之间距离
typedef typename Iterator::pointer pointer // 指向迭代器所指的对象
typedef typename Iterator::reference reference // 迭代器所指对象的引用
}

正是迭代器的 5 种类型和iterator_traits技法成就了所谓的“C++编译期间的多态”。

最后

如果你有疑惑,欢迎评论,我会尽可能回复!

如果本文对你有帮助,点个赞吧,这是我坚持的动力!

iterator_traits技法的更多相关文章

  1. STL源码--iterator和traits编程技法

    第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...

  2. STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法

    1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...

  3. STL Traits编程技法

    traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...

  4. [转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法

    本文从三方面总结迭代器   迭代器的思想   迭代器相应型别及traits思想   __type_traits思想 一 迭代器思想 迭代器的主要思想源于迭代器模式,其定义如下:提供一种方法,使之能够依 ...

  5. 带你深入理解STL之迭代器和Traits技法

    在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...

  6. STL——迭代器与traits编程技法

    一.迭代器 1. 迭代器设计思维——STL关键所在 在<Design Patterns>一书中对iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素 ...

  7. STL源码之traits编程技法

    摘要 主要讨论如何获取迭代器相应型别.使用迭代器时,很可能用到其型别,若需要声明某个迭代器所指对象的型别的变量,该如何解决.方法如下: function template的参数推导机制 例如: tem ...

  8. STL源码剖析——iterators与trait编程#2 Traits编程技法

    在算法中运用迭代器时,很可能用到其相应类型.什么是相应类型?迭代器所指对象的类型便是其中一个.我曾有一个错误的理解,那就是认为相应类型就是迭代器所指对象的类型,其实不然,相应类型是一个大的类别,迭代器 ...

  9. 迭代器iterator和traits编程技法

    前言 这段时间研读SGI-STL-v2.91源码,并提炼核心代码自己实现一遍,感觉受益颇深.觉得有必要写一些文章记录下学习过程的思考,行文旨在总结,会大量参考侯捷<STL源码剖析>的内容. ...

  10. STL之traits编程技法

    traits编程技法利用了“内嵌型别”的编程技巧与编译器的template参数推导功能. 下面主要看看利用traits编程技法实现的迭代器萃取机制. 5种迭代器类型定义: struct input_i ...

随机推荐

  1. ES 客户端 RestHighLevelClient Connection reset by peer 亲测有效 2022-11-05

    导读 最新公司ES集群老出现连接关闭,进而导致查询|写入ES时报错,报错日志显示如下 [2m2022-10-23 14:13:10.088[0;39m - [31mERROR[0;39m - [35m ...

  2. php 程序员进化之路

    1.目标明确 2.消除干扰 3.自我激励 鸟哥 --2018年11月17日php年会

  3. 关于linux fcitx输入法候选词中含有省略号的问题解决

    前言 这几天舍弃了 sogou 输入法,换上了google拼音输入法,因为我在纯文本终端调用中文输入法,搜狗显示出来的是加密的,候选词都是加密的,很烦这种 问题原因 这个问题主要是因为 云拼音 模块凉 ...

  4. 程序员面试干货:漫谈计算机网络:数据链路层 ----- 数据链路路在何方? --从点对点数据传输 到 "广泛撒网,重点捕获"的局域网

    面试答不上?计网很枯燥? 听说你学习 计网 每次记了都会忘? 不妨抽时间和我一起多学学它 深入浅出,用你的空闲时间来探索计算机网络的硬核知识! 博主的上篇连载文章<初识图像处理技术> 图像 ...

  5. 【Java EE】Day03 DQL、约束、数据库设计、范式、备份和还原

    〇.总结 1.DQL 聚合函数有空值需要使用ifnull函数 where不能使用聚合函数 分页开始索引的计算,及mysql和oracle的方言 2.约束 删除唯一约束DROP INDEX 列名; 3. ...

  6. python2和python3的区别(1)

    1.python2和python3的解释器的默认编码不同 python2解释器的编码默认用的是 ascii python3解释器的编码默认用的 utf-8 2.python2和python3输入的表示 ...

  7. Flask框架使用SQLAlchemy的ORM

    SQLAlchemy 1.介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然后使用 ...

  8. python基础re模块与正则

    正则表达式前戏 正则表达式是用来匹配与查找字符串的,从网上爬取数据自然或多或少会用到正则表达式,python的正则表达式要先引入re模块,正则表达式以r引导 案例:手机号校验 基本要求:手机号必须是1 ...

  9. 一文速览 Dubbo 3.0

    本文将带你快速了解 Dubbo3 的设计背景.总体架构与核心特性.与典型用户如阿里巴巴 HSF2 的关系等.也可以通过如下部分了解更多: 小白用户,快速浏览 Dubbo3 核心特性: 下一代通信协议 ...

  10. VMware虚拟机开机黑屏解决方法

    挂起时可以看到显示,但是开机就黑屏 解决方法: 命令提示符,鼠标右键点击"命令提示符",弹出菜单之后选择"以管理员身份运行" 在命令提示符窗口中输入" ...