Как получить номер цикла при использовании итератора в C ++? - PullRequest
2 голосов
/ 12 июня 2010

Я работаю над приложением, в котором я рисую пару изображений, например:

void TimeSlice::draw(float fX, float fY) {
list<TimeSliceLevel*>::iterator it = levels.begin();
float level_x = x;
float level_y = y;
while(it != levels.end()) {
    (*it)->draw(level_x,level_y);
    level_y += (*it)->height;
    ++it;
}

}

Хотя это немного неправильно.Мне нужно расположить TimeSliceLevel * на X .. Когда у меня есть цикл for(int i = 0; i < slices.size(); ++i), я могу использовать x = i * width.Хотя я использую итератор, как мне много раз говорили, это хорошее программирование:> и мне интересно, есть ли у итератора индексное число, которое я могу использовать для вычисления новой позиции X?(Так что это больше вопрос об использовании итераторов)

С уважением, Pollux

Ответы [ 6 ]

7 голосов
/ 12 июня 2010

Это не так, поскольку итераторы могут использоваться для других целей, помимо циклического перемещения от начала до конца упорядоченного индексированного списка. Вам нужно будет отслеживать индекс отдельно и увеличивать его при каждом проходе:

list<TimeSliceLevel*>::iterator it;
int index;

for(it = levels.begin(), index = 0; it != levels.end(); ++it, ++index) {
    ...
}
3 голосов
/ 12 июня 2010

Нет, это не так.Если вам нужен целочисленный индекс, используйте цикл for.Несмотря на то, что некоторые экстремисты-итераторы поверили бы, циклы for все еще имеют свое место в коде C ++.

2 голосов
/ 12 июня 2010

Можно перейти из итератора -> индекс. Есть как минимум два способа:

  1. Используйте - для итераторов произвольного доступа (т.е. i - container.begin())
  2. Используйте std::distance (т.е. std::distance(containter.begin(), i)). Это более «универсальное» решение, которое в случае итератора произвольного доступа будет работать идентично - благодаря специализации, но в противном случае будет иметь ужасное влияние на производительность

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

1 голос
/ 12 июня 2010

Для некоторых типов итераторов просто вычтите текущий итератор из исходного итератора:

index = it - levels.begin()

Поскольку это не работает для итераторов std :: list, просто отслеживайте индекс явнос переменной, как указано в ответах выше.Преимущество использования итератора и контейнера не теряется.Вы добавляете требование, которое контейнер не предоставляет.

0 голосов
/ 12 июня 2010

Вы МОЖЕТЕ НО ТОЛЬКО для итератора с произвольным доступом.Если это итератор с произвольным доступом, вы можете вычесть ваш итератор из начального итератора, чтобы получить индекс (без сохранения отдельной переменной индекса int).

for (vector<int>::const_iterator cit = v.begin(); cit != v.end(); ++cit)
{
   cout << "This is element no: " << cit - v.begin() << endl;
}

В вашем примере, к сожалению, вы не сможете сделатьэто потому, что вы используете std :: list, который является только двунаправленным итератором.Используйте std :: vector, и вы можете сделать это, как в моем примере.

0 голосов
/ 12 июня 2010

Вы должны написать что-то вроде

size_t index = 0;
for (list<...>::const_iterator it = y.begin(); it != y.end(); ++it) {
   // Do your actions based on `index`
   ++index;
}

и, ну, это иногда подходит.

С другой стороны, вы можете провести рефакторинг (перепланировка) вашего приложения, чтобы ваш цикл рисования не обязательно выполнял все эти x += something, y += something2, ..., а действовал следующим образом:

foreach (Level* level, list) {
    level->draw(backend);
}

Иногда это может быть сложно, но, на мой взгляд, такой подход может сэкономить вам много времени, если ваше приложение вырастет до чего-то «большого».

...