iterator_traits技法
问题
在 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技法的更多相关文章
- STL源码--iterator和traits编程技法
第一部分 iterator学习 STL iterators定义: 提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达方式. 任何iteartor都应该提供5 ...
- STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法
1.准备知识 typename用法 用法1:等效于模板编程中的class 用法2:用于显式地告诉编译器接下来的名称是类型名,对于这个区分,下面的参考链接中说得好,如果编译器不知道 T::bar 是类型 ...
- STL Traits编程技法
traits编程技法大量运用于STL实现中.通过它在一定程度上弥补了C++不是强型别语言的遗憾,增强了C++关于型别认证方面的能力. traits编程技法是利用“内嵌型别”的编程技法和编译器的temp ...
- [转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法
本文从三方面总结迭代器 迭代器的思想 迭代器相应型别及traits思想 __type_traits思想 一 迭代器思想 迭代器的主要思想源于迭代器模式,其定义如下:提供一种方法,使之能够依 ...
- 带你深入理解STL之迭代器和Traits技法
在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...
- STL——迭代器与traits编程技法
一.迭代器 1. 迭代器设计思维——STL关键所在 在<Design Patterns>一书中对iterator模式定义如下:提供一种方法,使之能够依序巡访某个聚合物(容器)所含的各个元素 ...
- STL源码之traits编程技法
摘要 主要讨论如何获取迭代器相应型别.使用迭代器时,很可能用到其型别,若需要声明某个迭代器所指对象的型别的变量,该如何解决.方法如下: function template的参数推导机制 例如: tem ...
- STL源码剖析——iterators与trait编程#2 Traits编程技法
在算法中运用迭代器时,很可能用到其相应类型.什么是相应类型?迭代器所指对象的类型便是其中一个.我曾有一个错误的理解,那就是认为相应类型就是迭代器所指对象的类型,其实不然,相应类型是一个大的类别,迭代器 ...
- 迭代器iterator和traits编程技法
前言 这段时间研读SGI-STL-v2.91源码,并提炼核心代码自己实现一遍,感觉受益颇深.觉得有必要写一些文章记录下学习过程的思考,行文旨在总结,会大量参考侯捷<STL源码剖析>的内容. ...
- STL之traits编程技法
traits编程技法利用了“内嵌型别”的编程技巧与编译器的template参数推导功能. 下面主要看看利用traits编程技法实现的迭代器萃取机制. 5种迭代器类型定义: struct input_i ...
随机推荐
- 自动化运维?看看Python怎样完成自动任务调度⛵
作者:韩信子@ShowMeAI Python3◉技能提升系列:https://www.showmeai.tech/tutorials/56 本文地址:https://www.showmeai.tech ...
- 46.drf过滤、搜索、排序
DRF的过滤类 drf过滤器在filters模块中,主要有四个类 BaseFilterBackend:过滤基类,留好占位方法待后续继承 SearchFilter:继承BaseFilterBackend ...
- 强软弱引用,ThreadLocal和内存泄漏
强引用 写法:Object obj=new Object() 引用强度:最强 只要被引用着,就不会被gc(垃圾回收)回收掉. 软引用 写法:SoftReference<String> sr ...
- 【iOS逆向】某营业厅算法分析
阅读此文档的过程中遇到任何问题,请关注公众号[移动端Android和iOS开发技术分享]或加QQ群[812546729] 1.目标 使用frida stalker分析某营业厅的签名算法. 2.操作环境 ...
- ubuntu 20.04 / 22.04 运行32位程序
sudo dpkg --add-architecture i386 sudo apt install libc6:i386 libstdc++6:i386 sudo apt-get update su ...
- (C++) C++ 中 shared_ptr weak_ptr
shared_ptr std::shared_ptr<int> sp1 = new int(); // shared count = 1, weak count = 0 std::shar ...
- Jvm上如何运行其他语言?JSR223规范最详细讲解
一 在Java的平台里,其实是可以执行其他的语言的.包括且不仅限于jvm发展出来的语言. 有的同学可能会说,在java项目里执行其他语言,这不吃饱了撑着么,java体系那么庞大,各种工具一应俱全,放着 ...
- LeetCode HOT 100:下一个排列
题目:31. 下一个排列 题目描述: 本题是给你一个整数数组,返回该数组的下一个线性顺序排列. 举个例子:给你一个[1, 2, 3]的数组,他的线性排列顺序从小到大依次为[1, 3, 2],[2, 1 ...
- 通过 CancellationToken 提高 Web 性能
在 Web 开发中,经常会遇到这样的场景:用户发起一个请求,Web 服务器执行一些计算密集型的操作,等待结果返回给用户.这种情况下,如果用户在等待结果的过程中取消了请求,那么服务器端依然会继续执行计算 ...
- JavaScript:对象:如何去遍历输出一个对象的属性?语句for-in
使用for-in的for循环语句,可以去遍历一个对象的属性,这类似于Java的增强for循环: 但是注意,这并不能遍历对象的所有属性,有些隐藏的属性,是无法遍历出来的,虽然我们可以通过控制台去查看这些 ...