Search code examples
c++vectorstliteratorconst-iterator

Iterator VS const_iterator, using it with distance()


Just a question, on the use of const_iterator vs just iterator. More specifically with the use of distance(). Below is some basic code that just craps out a list of "fav_games" that the user enters (earlier in the application). I wanted to also crap out the 'index' of the vector so as to print out a numbered list.

Partial Code:

int main()
{
    vector<string> fav_games;
    vector<string>::const_iterator iter; // const_iterator no worky with "distance()"

    if (fav_games.size() > 0)  {
        cout << "\n\nCurrent game list: \n";
        for (iter = fav_games.begin(); iter != fav_games.end(); ++iter) 
        {
            cout << distance(fav_games.begin(), iter) << ". " << *iter << endl;
        }
    }

    return 0;
}

My question is why, "const_iterator" will not work, where I am forced to use "iterator" instead. Looking for the 'theory' behind it. "distance()" appears to expecting and "iterator" -- not "const_iterator". ..Why?

Just for reference the compile error if I use "const_iterator":

Error 1 error C2782: 'iterator_traits<_Iter>::difference_type std::distance(_InIt,_InIt)' : template parameter '_InIt' is ambiguous z:\micah\c++\favgames\favgames\favgames.cpp 49 1 favgames

Thanks!


Solution

  • Try this instead:

    vector<string>::const_iterator b, iter, e;
    
    if (fav_games.size() > 0)  {
        cout << "\n\nCurrent game list: \n";
        for (b = fav_games.begin(), iter = b, e = fav_games.end(); iter != e; ++iter) 
        {
            cout << distance(b, iter) << ". " << *iter << endl;
        }
    }
    

    distance has no problem with two const_iterator instances, or two iterator instances. Your mistake was in mixing them.

    Still, making O(n) calls to distance is crazy. Just use a counter:

    vector<string>::const_iterator iter, e;
    size_t i;
    
    if (fav_games.size() > 0)  {
        cout << "\n\nCurrent game list: \n";
        for (i = 0, iter = fav_games.begin(), e = fav_games.end(); iter != e; (++iter), (++i)) 
        {
            cout << i << ". " << *iter << endl;
        }
    }
    

    In C++11 and later, one may of course go one step further and avoid explicit use of the iterators at all:

    if (fav_games.size() > 0) {
        int i = 0;
        cout << "\n\nCurrent game list: \n";
        for (const string& game : fav_games) 
        {
            cout << (i++) << ". " << game << endl;
        }
    }