问题

在 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++编译期间的多态”。

最后

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

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

最新文章

  1. 使用IntelliJ IDEA 配置Maven(入门)【转】
  2. k8s总结(图片打开略慢请知晓)
  3. Atitit.excel导出 功能解决方案 php java C#.net版总集合.doc
  4. B树、B-树、B+树、B*树---转载
  5. jackson 解析结合类(需要传入Class, 和 Class.Class, 回调方法是List&lt;Class&gt;)
  6. ckplayer网页播放器简易教程
  7. 线程同步synchronized
  8. 为图片存储而作——记一次UEditor源码的修改
  9. eazasyui树形菜单
  10. 更自然的解决字典数组插入nil而导致crash
  11. 如何让Vim成为我们的神器
  12. 3.python元组与列表
  13. ES6 let和const命令(4)
  14. 通过 mysqlbinlog 和 grep 命令定位binlog文件中指定操作
  15. matlab常用目录操作
  16. 一致性哈希算法----nginx负载均衡器配置之一
  17. CRT乱码问题
  18. spring mvc get请求中文乱码问题
  19. advanced installer重新打包教程
  20. Vue.JS React 精彩文章汇总

热门文章

  1. 使用 StringUtils.split 的坑
  2. 「浙江理工大学ACM入队200题系列」问题 H: 零基础学C/C++18——三位数反转
  3. 带你从0到1开发AI图像分类应用
  4. 设计模式学习(二十四):Spring 中使用到的设计模式
  5. 如何实现一个优秀的 HashTable 散列表?
  6. 2022-2023年度必备宇宙最全Windows系统软件清单
  7. .NET 6 实现滑动验证码(二)、基本数据
  8. 疫情可视化part3
  9. Django基础笔记5(Session)
  10. 【每日一题】【DFS+存已加的值】2022年2月27日-二叉树根节点到叶子节点的所有路径和