一、从模板函数std::distance(计算迭代器的距离)开始
#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <stack>
#include <set>
#include <map>
int main(int argc, char*argv[])
{
std::vector<int> vec;
for (int i = 0; i < 10; ++i)
{
vec.push_back(i);
}
///stack、queue、priority_queue无迭代器
///vector、deque有operator-的实现,而list、set、map没有
auto d = vec.end() - vec.begin();
///distance函数对各类型迭代器都支持,计算迭代器之间的距离
auto itrDis = std::distance(vec.begin(), vec.end());
return 0;
}
1、stack、queue、priority_queue容器无迭代器,即不能使用此函数。
2、vector、deque容器重载了operator-,实现了计算std::distance功能。内存连续型(迭代器可跳跃)容器,距离为迭代器直接相减。
_NODISCARD difference_type operator-(const _Mybase& _Right) const
{ // return difference of iterators
return (*(_Mybase *)this - _Right);
}
3、list、set、map容器没有实现operator-,内存不连续型(迭代器不可跳跃)容器。
二、distance模板函数实现剖析
//_Distance1的两个重载版本begin
template<class _InIt>
_CONSTEXPR17 _Iter_diff_t<_InIt> _Distance1(_InIt _First, _InIt _Last, input_iterator_tag)
{ // return distance between iterators; input
_Iter_diff_t<_InIt> _Off = 0;
for (; _First != _Last; ++_First)
{
++_Off;
}
return (_Off);
}
template<class _RanIt>
_CONSTEXPR17 _Iter_diff_t<_RanIt> _Distance1(_RanIt _First, _RanIt _Last, random_access_iterator_tag)
{ // return distance between iterators; random-access
return (_Last - _First);
}
//_Distance1的两个重载版本end
//迭代器的类型萃取begin
template<class _Iter>
using _Iter_cat_t = typename iterator_traits<_Iter>::iterator_category;
//迭代器的类型萃取end
//distance函数begin
template<class _InIt>
_NODISCARD _CONSTEXPR17 _Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last)
{ // return distance between iterators
return (_Distance1(_First, _Last, _Iter_cat_t<_InIt>()));
}
//distance函数end
1、由_Distance1函数实现,并且_Distance1有两个重载版本(VS2017),其他编译器可能有多个,但并无分别。
2、由第三参数类型input_iterator_tag和random_access_iterator_tag用来重载,也仅仅是用来重载,并未使用类型对象。
3、_Iter_cat_t<_InIt>()则用来萃取(向迭代器提问)其类型,而iterator_category即是答案。
typename T::iterator_category cagy2; //等同于迭代器的类型萃取
4、迭代器除了可以回答与之容器对应的迭代器类型,还可以回答一下类型。
typedef bidirectional_iterator_tag iterator_category //迭代器的分类
typedef ptrdiff_t difference_type //iterator之间的距离
typedef size_t size_type //分配内存大小
typedef T value_type
typedef T* pointer
typedef &T reference
例如:
typename std::iterator_traits<T>::difference_type diff_type;
5、迭代器的五种类型,按移动性质分类,不是枚举、常量宏等类型,为struct,属性在此等同class,并且有继承关系。
struct input_iterator_tag
{ // identifying tag for input iterators
};
struct output_iterator_tag
{ // identifying tag for output iterators
};
struct forward_iterator_tag
: input_iterator_tag
{ // identifying tag for forward iterators
};
struct bidirectional_iterator_tag
: forward_iterator_tag
{ // identifying tag for bidirectional iterators
};
struct random_access_iterator_tag
: bidirectional_iterator_tag
{ // identifying tag for random-access iterators
};
6、_Distance1模板函数只实现的两个重载版本(内存是否连续型或者说迭代器是否可跳跃),因为继承关系其他类型向上兼容。VS2017只有该两个版本,其他版本编译器可能有多个版本。
到此完完全全讲清楚了模板函数std::distance怎么实现计算迭代器之间的距离。
如对容器的数据结构,底层实现不清楚的可参考:
C++STL容器总结:https://blog.csdn.net/qq_43148810/article/details/118229552
7.拓展:
std::advance
:令迭代器移动给定距离。内部实现和distance原理一致,有兴趣可深入研究。
template<class _InIt,class _Diff> inline
void advance(_InIt& Where,_Diff _Off)
{...}
三、类型萃取,惊鸿一瞥 ,STL六大组件关系
总结:Container通过Allocator取得数据的储存空间,Algorithm通过Iterator存取Container内容,Functor可以协助Algorithm完全不同的策略变化,Adapter可以修饰或者套接Functor。
1、std::distance(计算迭代器的距离)算法很好的解释了以上“总结”斜线部分。
2、STL称之为标准模板库,C++面对对对象语言,标准库多为模板编程、元编程的手法,而非面对对象的手法。换而言之多为静态多态性,而非虚函数代表的动态多态性。
3、traits(萃取机)并非六大组件,但是在STL中起到至关重要的作用。
4、由此打开元编程(对类型操作,而非对象)的大门
如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810