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的
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章