0

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;
}
2
  • 1
    If you need such control over the loop, it's best - clearer, more readable - to spell out the iterator-based loop, and not attempt pointer arithmetic. Commented Aug 6, 2019 at 0:22
  • 1
    The problem with your attempt is that *(&x+1) exhibits undefined behavior when x refers to the last element. With range-based loop, there's no way to stop one element short of the end. Commented Aug 6, 2019 at 0:24

3 Answers 3

4

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();
}
Sign up to request clarification or add additional context in comments.

1 Comment

I feel that adjacent_find is the way to go in this case.
1

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.

2 Comments

okay, just wanted to know what's wrong with my try to refer to the next element with *(&x+1) I've been learning these range based looped today and it seemed like a simple problem at first, so I've been sure that it is possible to solve without creating a variable.
@Olgierd The problem with your attempt is that *(&x+1) exhibits undefined behavior when x refers to the last element. With range-based loop, there's no way to stop one element short of the end. – Igor Tandetnik 16 mins ago
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.