问题

在 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. day08-XML

    XML 官方文档:https://www.w3school.com.cn/xml/index.asp 1.为什么需要xml? 需求1:两个程序间进行数据通信? 需求2:给一台服务器,做一个配置文件,当 ...

  2. JAVA的File对象

    文件 1.File对象 java封装的一个操作文件及文件夹(目录)的对象.可以操作磁盘上的任何一个文件和文件夹. 2.创建文件  方式一:根据路径构建一个File对象new File(path) // ...

  3. chronyd为隔离网络设置时间同步

    参考链接:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_basic ...

  4. c# Winfrom桌面软件自动升级系统

    对于开发桌面应用升级应该是我们第一个要考虑的.一般而言一个项目只有一个客户端,有的时候一个项目可能分好几个客户端,前台客户端,后台客户端.而我在网上找了很久也没有找到可以同时管理多个客户端升级的.所以 ...

  5. C温故补缺(九):字节对齐与排序

    字节对齐与排序 字节对齐的原因与字节排序 取自:VisualEther 原文档下载:Gitee _packed _packet用于结构体中变量在内存中的对齐.如 typedef struct test ...

  6. 【kafka】JDBC connector进行表数据增量同步过程中的源表与目标表时间不一致问题解决

    〇.参考资料 一.现象 1.Oracle源表数据 2.PG同步后的表数据 3.现象 时间不一致,差了8个小时 4.查看对应的connector信息 (1)source { "connecto ...

  7. SpringMVC03:SSM整合

    一.搭建整合环境 1.ssm整合说明 2.搭建环境 二.Spring框架代码的编写 1.编写Spring框架(处理业务层) applicationContext.xml <?xml versio ...

  8. 大数据-业务数据采集-FlinkCDC

    CDC CDC 是 Change Data Capture(变更数据获取)的简称.核心思想是,监测并捕获数据库的变动(包括数据或数据表的插入.更新以及删除等),将这些变更按发生的顺序完整记录下来,写入 ...

  9. Python实验报告(第8章)

    实验8:模块 一.实验目的和要求 1.了解模块的内容: 2.掌握模块的创建和导入方式: 3.了解包结构的创建和使用. 二.实验环境 软件版本:Python 3.10 64_bit 三.实验过程 1.实 ...

  10. 如何配置 SLO

    前言 无论是对外提供 IaaS PaaS SaaS 的云公司,还是提供信息技术服务的乙方公司,亦或是金融 制造等各行各业的数据中心.运维部门,我们的一个非常重要的合同承诺或考核评估指标就是:SLA(即 ...