結論: 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的
}