Reset a range based for loop

In the traditional for loop, you could make the loop start again by resetting the int value

1
2
3
4
for (int i = 0; i < 10: ++i){
  //Do something
   i =0;
}


Then it would start the loop again. However I can not seem to find a way to do this with the range based for loop.

Is there anyway to force a range based for loop to start from, i = 0 ?

1
2
3
4
for(const auto &i : vec){
  //Do something
  //Restart for loop
}
Last edited on
As far as I know there is no easy way to do this (without building some wrapper on top of everything etc). If you need this kind of behavior you might as well just stay with the "traditional" style.

I know a lot of people dislike ranged based for loops for limitations like this.
Technically you could put a label before the for loop and use goto under certain conditions to reset it, but then everyone will complain you used goto and it will rain fire and all that stuff.

Personally I would stay with your first example.
You would have to play compiler to do that. The range-based for loop is syntactic sugar for something like this*:

1
2
3
4
5
for (type_of_xs::const_iterator xi = xs.begin(); xi != xs.end(); ++xi)
{
  const type_of_x& x = *xi;
  ...
}
1
2
3
4
for (const auto& x : xs)
{
  ...
}

* It's actually a bit more complicated than this, but it ultimately compiles to about the same thing.

What this means is that you do not have direct access to the range iterator itself.

Boost provides range adaptors for the most useful things. For example, if you want to iterate over only part of a range:
http://www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/adaptors/reference/sliced.html

What you are asking to do sounds a little unkosher anyway. You might want to rethink your algorithm.

So, uh, what are you trying to do? Anything interesting?

Hope this helps.
> Is there anyway to force a range based for loop to start from, i = 0 ?

1
2
3
4
restart: for(const auto &i : vec){
  //Do something
  goto restart ; //Restart for loop
}

http://coliru.stacked-crooked.com/a/0fda49e64f2e3633
So, uh, what are you trying to do? Anything interesting?


Im part of a SAT solver, the clause propagation.

I'm looping through the vector removing certain elements, but I have found that when i remove one element from the vector, everything moves up one place to fill the gap, as it should.

However the for loop is moving onto the next element, which effectively means it is skipping the element which took the removed elements place

If this makes sense?
You don't want a range-based for in the vicinity of iterator-invalidating operations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> seq { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
        
    // remove odd elements as we are iterating
    for( auto iter = std::begin(seq) ; iter != std::end(seq) ;  )
    {
        if( *iter % 2 ) 
        {
            std::cout << "removing " << *iter << '\n' ;
            iter = seq.erase(iter) ; // returns an iterator to the elment immediately after 
                                     // the element that was removed (or end if there is none).
        }
        else ++iter ; // not erased; so increment iter
    }
        
    for( int v : seq ) std::cout << v << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/f6b298afaa84d72c
JLBorges this makes sense, and I think would work, is there a way to adapt it for a vector of sets?

To clarify, I'm using a vector of sets. So this was my range based loop which would go through every set,

for(const auto &mySet : clauseVector){

This would return mySet, which was a set from the array

Im thinking this is trivial, but something is not quite clicking with me to translate it to code
> is there a way to adapt it for a vector of sets?
> Im thinking this is trivial

It is trivial; and it works with any sequence container.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <list>
#include <set>
#include <numeric>

int main()
{
    std::list< std::set<int> > seq { { 0, 25, 7 }, { 1, 6, 12 }, { 20, 21, 22 }, { 1, 3, 7, 8 }, { 5, 6, 7, 8, 9 } } ;
    
    const auto print = [] ( const std::set<int>& set ) 
                          { std::cout << "[ " ; for( int v : set ) std::cout << v << ' ' ; std::cout << "]\n" ; } ;
        
    // as we iterate, remove sets which sum up to 19
    for( auto iter = std::begin(seq) ; iter != std::end(seq) ;  )
    {
        const auto& set = *iter ;
        if( std::accumulate( set.begin(), set.end(), 0 ) == 19 ) 
        {
            std::cout << "removing set " ;
            print(set) ;
            
            iter = seq.erase(iter) ; // returns an iterator to the elment immediately after 
                                     // the element that was removed (or end if there is none).
        }
        else ++iter ; // not erased; so increment iter
    }
     
    std::cout << "\nthe sequence now contains:\n" ;
    for( const auto& set : seq ) print(set) ;
}

http://coliru.stacked-crooked.com/a/3049368879dea914

The erase-remove idiom may be more appropriate.
http://www.cplusplus.com/forum/general/129501/#msg699368
Snnnider wrote:
I'm part of a SAT solver, the clause propagation.

I'm looping through the vector removing certain elements, but I have found that when i remove one element from the vector, everything moves up one place to fill the gap, as it should.

However the for loop is moving onto the next element, which effectively means it is skipping the element which took the removed elements place

If this makes sense?


Using the traditional for loop, you could decrease the value of the index variable by one, after deleting an element, so it checks that same position again.

Aceix.
Topic archived. No new replies allowed.