乐趣区

iterator_traits获取迭代器类型

结论: std::iterator_traits 用于 Iterator 类型
比如有这么一个需求, 给随意的一个迭代器移动距离 , 伪代码:
template <typename Iter, typename Distance>
void move_iter(Iter& iter, Distance d)
{
if(iter is std::random_access_iterator_tag) // 随机迭代器随意加减
iter +=d;
else // 别的迭代器
….
}
问题是如何判断一个迭代器类型 , 使用 iterator_traits;
前提 , 5 种迭代器是继承关系 , 随意看一眼即可:
struct input_iterator_tag
{// identifying tag for input iterators
};

struct _Mutable_iterator_tag
{// identifying tag for mutable iterators
};
struct forward_iterator_tag
: input_iterator_tag, _Mutable_iterator_tag
{// identifying tag for forward iterators
};
….
看一下 iterator_traits:
template<class _Iter>
struct iterator_traits
{// get traits from iterator _Iter
typedef typename _Iter::iterator_category iterator_category;

还有一堆 typedef 的东西, 省略
}
iterator_traits 和 remove_reference 内部实现差不多, 只是一堆 typedef , 主要用于获取类型; 先简单看一下 iterator_traits 怎么用:
// 太长了?
// iterator_traits< 迭代器类型 >::iterator_category
//iterator_category 就是一个被 typedef 的 5 个结构体中的其中一个

cout << typeid(std::iterator_traits<list<int>::iterator>::iterator_category).name() << endl;
cout << typeid(std::iterator_traits<deque<int>::iterator>::iterator_category).name() << endl;

/*
输出:
struct std::bidirectional_iterator_tag
struct std::random_access_iterator_tag
*/
用于判断迭代器类型的就是 iterator_category , 而他本身就是 5 种迭代器的其中一个;
接下来就可以修改第一份伪代码了 . 大致是这样:
template <typename Iter, typename Distance>
void move_iter(Iter& iter, Distance d)
{
if(typeid(std::random_access_iterator_tag) == typeid(std::iterator_traits<Iter>::iterator_category))
iter += d;
else if …

}
用 RTTI 这类东西总是觉得, 本来就可以在编译的时候完成的, 干嘛非等到运行时;
在修改一下 , 下面代码用了哑元 , 3 个重载的 template function:
template <typename Iter , typename Dist>
void do_move_iter(Iter & iter, Dist d , std::random_access_iterator_tag) // 随机迭代
{
iter += d;
}
template <typename Iter , typename Dist>
void do_move_iter(Iter & iter, Dist d , std::bidirectional_iterator_tag) // 双向
{
if(d>= 0){
while(d–)
++iter;
}
else {
while(d++)
–iter;
}
}
template <typename Iter , typename Dist>
void do_move_iter(Iter & iter, Dist d , std::input_iterator_tag) // forward 继承了 input;
{
if(d < 0)
throw std::out_of_range(“d < 0”);
while(d–)
++iter;
}

template <typename Iter, typename Distance>
void move_iter(Iter& iter, Distance d)
{
do_move_iter(iter,d, std::iterator_traits<Iter>::iterator_category());
}

int main()
{
vector<int> vi{1,2,3,4};
vector<int>::iterator iter = vi.begin(); // 随机迭代器
move_iter(iter,2); // 移动 2 个距离
cout << *iter << endl; //3. ok 的
}

退出移动版