views:

531

answers:

3

I have a BOOST_FOREACH loop to iterate over a list. Unfortunately, I also need to cache an iterator to a particular item.

typedef List::iterator savedIterator;

BOOST_FOREACH(Item &item, list)
{
// stuff...
  if (condition)
    savedIterator = &item; // this won't work

// do more stuff...     
}

Obviously I can do this using a list.begin()..list.end() for loop, but I've grown to like BOOST_FOREACH. Is there a way round this?

+4  A: 

This is not possible, as you do not have access to an iterator pointing to the current item inside the loop.

You could fetch an iterator from the list somehow using the current items data but I don't know if this is a good idea to follow, also performance-wise.

I'd suggest you use the solution you already proposed yourself with list.begin() .. list.end(), this is in my opinion the easiest to implement and recognize.

Kosi2801
+2  A: 

With Boost.Foreach, you're pretty much stuck with the reference to the dereferenced iterator since this is what Boost.Foreach was designed to do: simplify access to the elements in a range. However, if you're just looking for a single element that fits a criteria you might want to try std::find_if():

struct criteria {
  template <class T>
  bool operator()(T const & element) const {
    return (element /* apply criteria... */)? true : false;
  }
};

// somewhere else
List::iterator savedIterator =
  std::find_if(list.begin(), list.end(), criteria());

It also looks like you want to apply operations on the whole list -- in which case I'll suggest using something like std::min_element() or std::max_element() along with Boost.Iterators like boost::transform_iterator.

struct transformation {
  typedef int result_type;
  template <class T>
  int operator()(T const & element) const {
    // stuff
    int result = 1;
    if (condition) result = 0;
    // more stuff
    return result;
  }
};

// somewhere else
List::iterator savedIterator =
  std::min_element(
     boost::make_transform_iterator(list.begin(), transformation()),
     boost::make_transform_iterator(list.end(), transformation()),
  ).base();
Dean Michael
Upvoted, but only because it reminds me how much I hate C++ at times.
Roddy
A: 

i kind of wonder why people don't do this:

#define foreach(iter_type, iter, collection) \
 for (iter_type iter = collection.begin(); iter != collection.end(); ++iter)
thanks for the edit
What if `collection` is an expression with side-effects? Your macro will evaluate it twice. Also, the whole point of traditional `foreach` is to get values directly, without messing with iterators (and their lengthy unwieldy type names) at all.
Pavel Minaev