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++编译期间的多态”。
最后
如果你有疑惑,欢迎评论,我会尽可能回复!
如果本文对你有帮助,点个赞吧,这是我坚持的动力!
最新文章
- 使用IntelliJ IDEA 配置Maven(入门)【转】
- k8s总结(图片打开略慢请知晓)
- Atitit.excel导出 功能解决方案 php java C#.net版总集合.doc
- B树、B-树、B+树、B*树---转载
- jackson 解析结合类(需要传入Class, 和 Class.Class, 回调方法是List<;Class>;)
- ckplayer网页播放器简易教程
- 线程同步synchronized
- 为图片存储而作——记一次UEditor源码的修改
- eazasyui树形菜单
- 更自然的解决字典数组插入nil而导致crash
- 如何让Vim成为我们的神器
- 3.python元组与列表
- ES6 let和const命令(4)
- 通过 mysqlbinlog 和 grep 命令定位binlog文件中指定操作
- matlab常用目录操作
- 一致性哈希算法----nginx负载均衡器配置之一
- CRT乱码问题
- spring mvc get请求中文乱码问题
- advanced installer重新打包教程
- Vue.JS React 精彩文章汇总
热门文章
- 使用 StringUtils.split 的坑
- 「浙江理工大学ACM入队200题系列」问题 H: 零基础学C/C++18——三位数反转
- 带你从0到1开发AI图像分类应用
- 设计模式学习(二十四):Spring 中使用到的设计模式
- 如何实现一个优秀的 HashTable 散列表?
- 2022-2023年度必备宇宙最全Windows系统软件清单
- .NET 6 实现滑动验证码(二)、基本数据
- 疫情可视化part3
- Django基础笔记5(Session)
- 【每日一题】【DFS+存已加的值】2022年2月27日-二叉树根节点到叶子节点的所有路径和