Iterator VS const_iterator, используя его с Distance()

Просто вопрос об использовании const_iterator против простого итератора. В частности, с использованием расстояния(). Ниже приведен базовый код, который просто выводит список «fav_games», который вводит пользователь (ранее в приложении). Я также хотел вывести «индекс» вектора, чтобы распечатать нумерованный список.

Частичный код:

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;
}

Мой вопрос в том, почему «const_iterator» не будет работать, вместо этого я вынужден использовать «iterator». Ищите «теорию», стоящую за этим. "distance()" кажется ожидающим, а "iterator" - не "const_iterator". ..Почему?

Просто для справки об ошибке компиляции, если я использую "const_iterator":

Ошибка 1 ошибка C2782: 'iterator_traits‹_Iter>::difference_type std::distance(_InIt,_InIt)': параметр шаблона '_InIt' неоднозначен z:\micah\c++\favgames\favgames\favgames.cpp 49 1 favgames

Спасибо!


person Micah    schedule 14.12.2014    source источник
comment
Тип обоих аргументов distance должен быть одинаковым (если вы выводите аргумент шаблона). Итак, в C++11 вам приходилось использовать .cbegin() и const_iter. Вы также можете использовать для RandomAccessIterators -, например. iter - fav_games.begin()   -  person dyp    schedule 15.12.2014


Ответы (1)


Попробуйте это вместо этого:

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 нет проблем с двумя экземплярами const_iterator или двумя экземплярами iterator. Ваша ошибка была в том, что вы их смешали.

Тем не менее, совершать O(n) вызовы distance — это сумасшествие. Просто используйте счетчик:

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;
    }
}

В C++11 и более поздних версиях можно, конечно, пойти еще дальше и вообще избежать явного использования итераторов:

if (fav_games.size() > 0) {
    int i = 0;
    cout << "\n\nCurrent game list: \n";
    for (const string& game : fav_games) 
    {
        cout << (i++) << ". " << game << endl;
    }
}
person Ben Voigt    schedule 14.12.2014
comment
@dyp: вызов находится внутри цикла. Как там О(1)? Да, расстояние для RandomIterator дешево, но простой счетчик еще дешевле и не станет загадочно дорогим, если изменится контейнер. - person Ben Voigt; 15.12.2014
comment
Ах, я неправильно вас понял. Однако почему вас беспокоит производительность вычитания указателя на каждой итерации, а не целочисленного приращения? - person dyp; 15.12.2014
comment
Кажется, теперь я вижу. Это нонсенс концептуально. - person dyp; 15.12.2014
comment
Хороший! Избегание явного использования итераторов выглядит красиво и чисто. Я еще не зашел так далеко с С++ 11, но, надеюсь, скоро :) Спасибо за всю помощь. - person Micah; 15.12.2014