Iterators有不同的类型,每种类型都代表着不同的能力,它在重载某个行为时,是有用的,甚至有必要。通过iterators tags和iterator traits 重载可以实现。对于么一个iterator类型STL都提供一个
terator tag
,这个
terator tag
能被做一个
’table”.
namespace std {
struct output_iterator_tag {
};
struct input_iterator_tag {
};
struct forward_iterator_tag
: public input_iterator_tag {
};
struct bidirectional_iterator_tag
: public forward_iterator_tag {
};
struct random_access_iterator_tag
: public bidirectional_iterator_tag {
};
}
如果要写一个泛型代码,你也许不仅需要iterator category ,例如你可能需要迭代器引用的类型,所以STL提供了一个特殊的面板结构体来定义iterator traits ,这个结构体包含了所有关于an iterator 的信息。它被用于定义一个iterator类型的正常的接口。
namespace std {
template <class T>
struct iterator_traits {
typedef typename T::value_type value_type;
typedef typename T::difference_type difference_type;
typedef typename T::iterator_category iterator_category;
typedef typename T::pointer pointer;
typedef typename T::reference reference;
};
}
这个结构体的模板参数是 iterator.
这个结构体有两个有点:
1.
它保证一个
iterator
提供了所有的类型定义。
2.
它能被特殊的迭代器特化或部分特化。
例如
namespace std {
template <class T>
struct iterator_traits<T*> {
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef random_access_iterator_tag iterator_category;
typedef T* pointer;
typedef T& reference;
};
}
因此对于任何指向 T
的指针类型,它都是
random access iterator
种类。
怎么写一个泛型函数。
如果你写泛型函数没有用到 iterator_traits
,它的实现很简单。例如:
template <class OutPutIterator>
void display(OutPutIterator start,OutPutIterator end)
{
while(start!=end)
{
cout<<*start<<" ";
++start;
}
cout<<endl;
}
这个使用于任何顺序容器。
但有的时候能用到,为了不同 iterator
种类,你一定要有以下两步:
Step 1.
让你的模板函数调用另一个函数,该函数增加了一个iterator category参数。
例如:
template <class Iterator>
inline void foo (Iterator beg, Iterator end)
{
foo (beg, end,std::iterator_traits<Iterator>::iterator_category());
}
Step2
:
为每一个 iterator
种类实现一个函数实现:
template <class BiIterator>
void foo (BiIterator beg, BiIterator end,
std::bidirectional_iterator_tag)
{
...
}
// foo() for random access iterators
template <class RaIterator>
void foo (RaIterator beg, RaIterator end,
std::random_access_iterator_tag)
{
}
看下 advance()
函数的实现过程。
template <class Iterator>
typename std::iterator_traits<Iterator>::difference_type
distance (Iterator pos1, Iterator pos2)
{
return distance (pos1, pos2,std::iterator_traits<Iterator>::iterator_category());
}
//distance() for random access iterators
template <class RaIterator>
typename std::iterator_traits<RaIterator>::difference_type
distance (RaIterator pos1, RaIterator pos2,
std::random_access_iterator_tag)
{
return pos2 - pos1;
}
//distance() for input, forward, and bidirectional iterators
template <class InIterator>
typename std::iterator_traits<lnIterator>::difference_type
distance (Inlterator pos1, InIterator pos2,
std::input_iterator_tag)
{
typename std::iterator_traits<lnIterator>::difference_type d;
for (d=0; pos1 != pos2; ++pos1, ++d) {
;
}
return d;
}
如何定义一个 iterator
在定义自己的 iterator
时,你需要提供iterator traits。
有两种方法;
1. 提供必要的 iterator_traits
的五种类型。
2. 提供 iterator_traits
结构体的特化。
对于第一种方法, STL
提供了一个基类
iteratoe<>,
它用于类型的定义。你可以这样:
class MyIterator
: public std::iterator <std::bidirectional_iterator_tag,
type, ptrdiff_t, type*, type &> {
...
};
第一个参数是the iterator category, 第二个参数是元素类型type,第三个是差值类型(difference type),第四个是指针类型(pointer type),第五个是引用类型(reference type),最后三个是可选的,它们默认的类型: ptrdif_f_t,
type
*,
and
type
&
。
namespace std {
struct output_iterator_tag {
};
struct input_iterator_tag {
};
struct forward_iterator_tag
: public input_iterator_tag {
};
struct bidirectional_iterator_tag
: public forward_iterator_tag {
};
struct random_access_iterator_tag
: public bidirectional_iterator_tag {
};
}
如果要写一个泛型代码,你也许不仅需要iterator category ,例如你可能需要迭代器引用的类型,所以STL提供了一个特殊的面板结构体来定义iterator traits ,这个结构体包含了所有关于an iterator 的信息。它被用于定义一个iterator类型的正常的接口。
namespace std {
template <class T>
struct iterator_traits {
typedef typename T::value_type value_type;
typedef typename T::difference_type difference_type;
typedef typename T::iterator_category iterator_category;
typedef typename T::pointer pointer;
typedef typename T::reference reference;
};
}
这个结构体的模板参数是 iterator.
这个结构体有两个有点:
1.
2.
例如
namespace std {
template <class T>
struct iterator_traits<T*> {
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef random_access_iterator_tag iterator_category;
typedef T* pointer;
typedef T& reference;
};
}
因此对于任何指向 T
怎么写一个泛型函数。
如果你写泛型函数没有用到 iterator_traits
template <class OutPutIterator>
void display(OutPutIterator start,OutPutIterator end)
{
while(start!=end)
{
cout<<*start<<" ";
++start;
}
cout<<endl;
}
这个使用于任何顺序容器。
但有的时候能用到,为了不同 iterator
Step 1.
例如:
template <class Iterator>
inline void foo (Iterator beg, Iterator end)
{
foo (beg, end,std::iterator_traits<Iterator>::iterator_category());
}
Step2
为每一个 iterator
template <class BiIterator>
void foo (BiIterator beg, BiIterator end,
std::bidirectional_iterator_tag)
{
...
}
template <class RaIterator>
void foo (RaIterator beg, RaIterator end,
std::random_access_iterator_tag)
{
}
看下 advance()
template <class Iterator>
typename std::iterator_traits<Iterator>::difference_type
distance (Iterator pos1, Iterator pos2)
{
return distance (pos1, pos2,std::iterator_traits<Iterator>::iterator_category());
}
//distance() for random access iterators
template <class RaIterator>
typename std::iterator_traits<RaIterator>::difference_type
distance (RaIterator pos1, RaIterator pos2,
std::random_access_iterator_tag)
{
return pos2 - pos1;
}
//distance() for input, forward, and bidirectional iterators
template <class InIterator>
typename std::iterator_traits<lnIterator>::difference_type
distance (Inlterator pos1, InIterator pos2,
std::input_iterator_tag)
{
typename std::iterator_traits<lnIterator>::difference_type d;
for (d=0; pos1 != pos2; ++pos1, ++d) {
;
}
return d;
}
如何定义一个 iterator
在定义自己的 iterator
有两种方法;
1. 提供必要的 iterator_traits
2. 提供 iterator_traits
对于第一种方法, STL
class MyIterator
: public std::iterator <std::bidirectional_iterator_tag,
...
};
第一个参数是the iterator category, 第二个参数是元素类型type,第三个是差值类型(difference type),第四个是指针类型(pointer type),第五个是引用类型(reference type),最后三个是可选的,它们默认的类型: ptrdif_f_t,