Iglord
Iglord

Reputation: 3

How to change (move forward/backward) an iterator in range based for loop?

I just want to get an element that is in the next iteration (using range-based for loop)

I have tried something like that:

*(&x+1) is supposed to mean "i+1" if "i" would have been an iterator here

bool factorChain(std::vector<int> arr) {
    for(auto& x : arr)
    {
        if (*(&x+1)%x != 0) return false;
    }
    return true;
}

I want it to work like that, but with a range-based for loop:

bool factorChain(std::vector<int> arr) {
    for(int i=0; i<arr.size()-1; i++)
    {
        if(arr[i+1]%arr[i]!=0) return false;
    }
    return true;
}

or this might be more helpful:

bool factorChain(std::vector<int> arr) {
    for(std::vector<int>::const_iterator iter = arr.begin();
          iter != arr.end()-1; ++iter){
        if(*(iter+1)%*(iter)!=0) return false;
    }
    return true;
}

Upvotes: 0

Views: 1203

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

In general you cannot.

I have written iterators_of, a range adapter that takes a range and reyurns a range of the iterators.

You start with a range type:

template<class It>
struct range{
  It b,e;
  It begin()const{return b;}
  It end()const{return e;}
};

that is a minimal one.

Then an indexing iteratoroid:

template<class T>
struct indexing_iteratoid{
  using this_t=indexing_iteratoid;  
   T t;
   T operator*()const{return t;}
   void operator++()&{++t;}
   friend bool operator==(this_t const& lhs, this_t const& rhs){return lhs.t==rhs.t;}
   friend bool operator!=(this_t const& lhs, this_t const& rhs){return lhs.t!=rhs.t;}
};

again, minimal and stripped down.

template<class R>
auto iterstors_of(R&& r){
  using std::begin; using std::end;
  auto b=begin(r), e=end(r);
  return range{ indexing_iteratoid{ b },  indexing_iteratoid{ e } };
}

and now you can:

for(auto it:iterators_of( vec ) ){
}

and *it is an element, and *std::next(it) is the next element (care not to go over the end), etc.

Code is based off code that works, but this was typed on a phone and probabky has tpyos.

It is an iteratoid because it isn't an iterator; it just qualifies for for(:) loops.

It is indexing, because its primary use is to store size_t's: pass it 0 and r.size() and you count from 0 to size()-1.

Upvotes: 0

Igor Tandetnik
Igor Tandetnik

Reputation: 52471

If you are really bent on using range-based loop, you can do something like this:

bool factorChain(std::vector<int> arr) {
    int* prev = nullptr;
    for(auto& x : arr)
    {
        if (prev && x % *prev != 0) return false;
        prev = &x;
    }
    return true;
}

However, at this point it's likely clearer, more readable to just spell out an iterator-based or index-based loop, than to try and salvage range-based one.


Now, for extra subtlety points, how about something like this:

bool factorChain(std::vector<int> arr) {
    return std::adjacent_find(arr.begin(), arr.end(),
        [](int prev, int next) { return next % prev != 0; })
    == arr.end();
}

Upvotes: 4

L. F.
L. F.

Reputation: 20579

I just want to get an element that is in the next iteration (using range-based for loop)

The answer to your question is simple: don't abuse features. The range-for loop is for the simplest case where you want to traverse the array one by one. If you want fine-grained control over the traversal, don't use the range-for loop. Your last two approaches are fine, so don't over-complicate things.

By the way, arr should be passed by const reference to avoid unnecessary copy.

Upvotes: 1

Related Questions