0

I am adding some functionality to a previously built code. I have to loop over a list is steps of 2 and process the elements elements differently.

Here's my attempt.

for(auto list_it = std::next(list.begin()); list_it != list.end() ; std::advance(list_it,2)){

   // Do something

}

I am initializing list_it to point to the second element using next(list.begin()) Each iteration it moves forward by 2 advance(list_it,2)).

[Q]

I am unsure how to test the loop exit condition.

list_it != list.end() might not work if we skip over list.end() when advancing forward by 2.

Is there any standard way to deal with this issue? I might check skipped iterators for being list.end(), but I don't see this as a nice, scalable way with larger step sizes. (unless it turns out to be the only way).

User 10482
  • 855
  • 1
  • 9
  • 22

4 Answers4

1

Update : Modifying for generic size.

For step size of k, You can get size of List in O(n) or O(1) - depending upon C++ compiler. After that compute steps you're allowed to take by:

  size_t steps_allowed = list.size()/k; 
   // list.size() is O(n) for C++98 and O(1) for standard C++ 11.

Then loop over another variable i and inside loop termination condition check for i against steps_allowed.

H S
  • 1,211
  • 6
  • 11
1

You can't advance past the .end() iterator. You have to use either a counter, or check all intermediate iterators. For example:

template<class It>
void checked_advance(It& it, It last, std::size_t n) {
    while (n-- > 0 && it != last)
        ++it;
}

assert(!list.empty());
for (auto it = std::next(list.begin()); it != list.end(); 
     checked_advance(it, list.end(), step)) {
    // ...
}
Evg
  • 25,259
  • 5
  • 41
  • 83
0

You can change you condition to check and make sure the difference between the current iterator and the end iterator is more then the step amount. That would look like

for(auto list_it = std::next(list.begin()); 
    std::distance(list_it, list.end()) > step; 
    std::advance(list_it, step))
{

// Do something
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

With range-v3, you might do:

for (auto& e : list | ranges::view::drop(1) | ranges::views::stride(2)) {
    // e
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302