迭代器萃取
迭代器的特性
STL的5大部件:
- 容器(container):vector,list,deque,array,forward_list,map,set,unordered_map,unordered_set
- 算法(algorithm)
- 迭代器(iterator)
- 适配器(配接器):stack,queue,priority_queue
- 仿函数
- 空间配置器(内存池)
其中迭代器是算法和容器的桥梁,算法通过迭代器对容器中的数据进行处理,有些算法需要知道迭代器的某些特性,迭代器要能够回答算法的这些提问。
标准库在设计迭代器的时候给每一个迭代器设置了5种特性:
-
iterator_catagory
,迭代器的种类- 单向迭代器(forward iterator),例如forward_list的迭代器,unordered_map和unordered_set的迭代器,forward_lis只支持++操作
- 双向迭代器(bidirectional iterator),例如list的迭代器,map和set的迭代器,bidirectional_iterator支持++和–操作
- 随机访问迭代器(random access iterator),例如vector的迭代器,array的迭代器,deque的迭代器,random access iterator支持++,–,+=k,-=k操作。
在标准库中iterator_catagory表示迭代器的种类,实际上它只是一个标签,用以区分不同种类的迭代器,除此之外,没有其他的用途。
int main() { //使用萃取机得到迭代器的类型 cout << typeid(iterator_traits<deque<string>::iterator>::iterator_category).name() << endl;//struct std::random_access_iterator_tag cout << typeid(iterator_traits<set<string>::iterator>::iterator_category).name() << endl;//struct std::bidirectional_iterator_tag cout << typeid(iterator_traits<forward_list<string>::iterator>::iterator_category).name() << endl;//struct std::forward_iterator_tag return 0; }
random_access_iterator_tag是一个空实现的结构体。在sort算法中,需要传入的迭代器的种类就是random_access_iterator
template <class RandomAccessIterator, class Compare> void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
-
value_type
,迭代器进行解引用得到的元素的类型。int main() { iterator_traits<vector<int>::iterator>::value_type x; cout << typeid(x).name() << endl;//int iterator_traits<unordered_map<int, double>::iterator>::value_type y; cout << typeid(y).name() << endl;//struct std::pair<int const ,double> return 0; }
-
difference_type
,两个迭代器之间的距离用difference_type表示,STL容器迭代器的difference_type都是int.int main() { cout << typeid(iterator_traits<unordered_map<string, int>::iterator>::difference_type).name() << endl;//int cout << typeid(iterator_traits<vector<int>::iterator>::difference_type).name() << endl;//int cout << typeid(iterator_traits<list<string>::iterator>::difference_type).name() << endl;//int cout << typeid(iterator_traits<map<string, int>::iterator>::difference_type).name() << endl;//int return 0; }
-
pointer
,若迭代器指向的元素类型是int,那么pointer就是int*,即迭代器所指向的元素与其所对应的指针类型。int main() { cout << typeid(iterator_traits<map<int, char>::iterator>::pointer).name() << endl;//struct std::pair<int const ,char> * cout << typeid(iterator_traits<vector<double>::iterator>::pointer).name() << endl;//double * cout << typeid(iterator_traits<list<vector<int>>::iterator>::pointer).name() << endl;//class std::vector<int,class std::allocator<int> > * return 0; }
-
reference
,若迭代器指向的元素类型是int,那么这个迭代器的reference就是int&int main() { pair<const int, int> kv(1,1); iterator_traits<map<int, int>::iterator>::reference ref = kv; ref.second= 20; cout << kv.second << ref.second << endl; return 0; }
任何符合标准库规范的迭代器都应该有这5种类型,以list的iterator为例:
template<class T>
struct __list_iterator{
typedef struct std::bidirectional_iterator_tag iterator_catagory;
typedef T value_type;
typedef int difference_type;
typedef T* pointer;
typedef T& reference;
};
按照道理说是可以直接通过迭代器拿到这5种特性,但是由于有的迭代器是原生指针,例如vector的迭代器,因此才需要萃取机进行萃取得到这5种特性,原生指针不是一个类,不能进行各种typedef操作。
萃取机作为一个中间层应该有能力区分迭代器是原生指针还是泛化的指针。
萃取机
萃取机使用到的技术是模板的偏特化(partial specialization),如果迭代器是一个泛化的指针,那么萃取机的内部直接根据迭代器就能拿到它的5种特性,如果迭代器是原生指针,那么由萃取机负责定义这5种特性。
int main() {
list<string>::iterator::pointer p = nullptr;
list<string>::iterator::value_type s = "string";
list<string>::iterator::iterator_category x;
list<string>::iterator::difference_type y = 10;
list<string>::iterator::reference ref = s;
//list的迭代器不是原生指针,内部自带这5种特性,但是vector的迭代器可能就是原生指针,内部就没有这5中特性,此时就需要通过萃取机萃取得到。
return 0;
}
萃取机的实现
template<class Iterator>
struct iterator_traits{
typedef typename Iterator::iterator_catagory iterator_catagory;
typedef int difference_type;
typedef typename Iterator::value_type value_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
};
template<T>
struct itertator_traits<T*>{
//迭代器是原生指针
typedef struct std::random_access_iterator_tag iterator_catgory;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef int dufference_type;
};
template<T>
struct iterator_traits<const T*>{
//const迭代器且为原生指针
typedef T value_type;
typedef const T& reference;
typedef const T* pointer;
typedef const int defference_type;
typedef struct std::random_access_iterator_tag iterator_catagory;
}
萃取机因为有了2个偏特化的版本,在迭代器为原生指针时也能得到它的5种特性。