Как создать станд.:: итератор списка в цикле с инкрементом

Я пытаюсь сделать двойной цикл по станд.:: список для работы на каждую пару элементов. Однако я испытываю некоторые затруднения при инициализации второго итератора. Код, который я хотел бы написать:

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
    for(std::list<int>::iterator j = i+1; j != l.end(); ++j) {
        ...
    }
}

Это не работает, потому что итераторы списка не являются произвольным доступом, таким образом, Вы не можете сделать +1. Но я испытываю некоторые затруднения при нахождении аккуратной альтернативы; компилятор, кажется, не очень доволен std::list<int>::iterator j(i)++; на который у меня была некоторая надежда. Достижение, что я хочу, кажется, что я оказываюсь перед необходимостью иметь некоторый неловкий дополнительный инкремент, который не будет соответствовать структуре для цикла приятно.

Существуют очевидные альтернативы (использующий вектор, например!), но мне кажется, что должен быть некоторый довольно аккуратный способ сделать это, которое я просто не вижу в данный момент.

Заранее спасибо за любую справку :)

7
задан Peter 15 February 2010 в 22:59
поделиться

7 ответов

Как насчет:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
    for (std::list<int>::iterator j = i; ++j != l.end(); ) {
        // ...
    }
}
8
ответ дан 6 December 2019 в 06:49
поделиться

Существует java.lang.String.trim () , но это также удаляет ведущее пробельное пространство. Существует также RichString.stripLineEnd , но удаляет только \n и \r .

-121--4585723-
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
    std::list<int>::iterator j = i; ++j;
    for(; j != l.end(); ++j) {
        ...
    }
}

Назад в игру!

На самом деле, это довольно распространенный идиом в числовых алгоритмах, поэтому я не считаю его уродливым.

4
ответ дан 6 December 2019 в 06:49
поделиться
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
    std::list<int>::iterator j = i;
    for(std::advance(j, 1); j != l.end(); ++j) {
        ...
    }
}
9
ответ дан 6 December 2019 в 06:49
поделиться

Я просто ухожу от идеи, которая возникла в ответе dirkgently:

template <typename Iter, typename Dist>
Iter advance_copy(Iter pIter, const Dist& pOffset)
{
    std::advance(pIter, pOffset);

    return pIter;
}

// ...

typedef std::list<int> int_list;

for(int_list::iterator i = l.begin(); i != l.end(); ++i)
{
    for(int_list::iterator j = advance_copy(i, 1); j != l.end(); ++j)
    {
    }
}

Вы также можете создать другой класс служебных функций, чтобы сделать его кратким :

// for consistency,
template <typename Iter>
void increment(Iter& pIter)
{
    ++pIter;
}

template <typename Iter>
Iter increment_copy(Iter pIter)
{
    return ++pIter;
}

// ...

typedef std::list<int> int_list;

for(int_list::iterator i = l.begin(); i != l.end(); ++i)
{
    for(int_list::iterator j = increment_copy(i); j != l.end(); ++j)
    {
    }
}
2
ответ дан 6 December 2019 в 06:49
поделиться

Прямая "аккуратная" альтернатива может быть основана на том, что list iterator - это объект пользовательского типа с перегруженными операторами (в отличие от встроенного типа). (Конечно, формально это не гарантируется, но этого можно ожидать, исходя из природы контейнера списка). По этой причине можно применить перегруженный оператор prefix ++ к временному объекту типа list iterator.

Чтобы добиться желаемого, достаточно создать временную копию i, увеличить ее с помощью префикса ++, а затем использовать полученное значение для инициализации j

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
  for(std::list<int>::iterator j = ++std::list<int>::iterator(i); j != l.end(); ++j) { 
    ... 
  } 
} 

И все. Обратите внимание, что этот трюк довольно популярен и может время от времени встречаться в реальном коде. Заметим также, что он обычно не работает с std::vector, поскольку многие реализации используют обычные встроенные указатели в качестве итераторов векторов, но он будет нормально работать с std::list.

Однако, лично я бы не стал использовать это в своем коде. Вы уже получили несколько хороших ответов, которые делают это, добавляя дополнительную строку кода.

2
ответ дан 6 December 2019 в 06:49
поделиться

Я бы выбрал предложение Шона, только сделал бы это циклом while:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) {
    std::list<int>::iterator j( i ); 
    while( ++j != l.end() ) {
        // ...
    }
}
1
ответ дан 6 December 2019 в 06:49
поделиться

Если вы уже используя Boost, тогда проще всего использовать boost :: next .

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i)
    for(std::list<int>::iterator j = boost::next(i); j != l.end(); ++j)
0
ответ дан 6 December 2019 в 06:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: