[Boost-users] BOOST_FOREACH with Index

1,573 views
Skip to first unread message

The Dude

unread,
Dec 13, 2009, 7:55:29 AM12/13/09
to boost...@lists.boost.org
  Hello,

  Boost::foreach is very useful for iterating over a sequence and doing something that depends only on the iterated element, e.g.,
<code>
BOOST_FOREACH(const Foo &f, foos)
  cout << f.bar() << endl;
</code>

  However, I often need to iterate over a sequence and do some operation that depends on both the iterated element and the iteration index. E.g., I would like something like
<code>
BOOST_FOREACH(size_t i, const Foo &f, foos)
  cout << "The bar of element " << i << " is " << f.bar() << endl;
</code>

  Is there an easy way to do so?

  Thanks & Bye,

  TD

Eric Niebler

unread,
Dec 13, 2009, 4:51:47 PM12/13/09
to boost...@lists.boost.org


Why not:

int index = 0;
BOOST_FOREACH(const Foo &f, foos)
{
// ... stuff ...
++index;
}

?

--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

The Dude

unread,
Dec 13, 2009, 5:18:25 PM12/13/09
to boost...@lists.boost.org
  Hello,

  Thanks for you answer. I'm not sure how to answer the "why not"? The code you write certainly will work, but so would the predecessor to BOOST_FOREACH in the first place, no? So here's my attempt:
1. For shorter loops, this changes 2 LOCs to 5.
2. For longer loops, the iteration code changes its meaning if it appears before the ++index or after.
3. The variable index has scope outside the loop.
4. Other people think so, e.g., the author's of D language http://en.wikipedia.org/wiki/D_(programming_language)#Example_1
  It's true that none of these points is really a proof. Still, I'd be really happy to hack my own INDEX_FOREACH, but the 500+ LOCs of BOOST_FOREACH left me daunted.

  Thanks & Bye,

  TD
 

Eric Niebler

unread,
Dec 13, 2009, 5:53:00 PM12/13/09
to boost...@lists.boost.org
The Dude wrote:

> Eric Niebler wrote:
>> Why not:
>>
>> int index = 0;
>>
>> BOOST_FOREACH(const Foo &f, foos)
>> {
>> // ... stuff ...
>> ++index;
>> }
>>
>> ?
>
> Thanks for you answer. I'm not sure how to answer the "why not"? The
> code you write certainly will work, but so would the predecessor to
> BOOST_FOREACH in the first place, no? So here's my attempt:
> 1. For shorter loops, this changes 2 LOCs to 5.

So put it all on one line! Kidding. ;-)

> 2. For longer loops, the iteration code changes its meaning if it
> appears before the ++index or after.
> 3. The variable index has scope outside the loop.
> 4. Other people think so, e.g., the author's of D language
> http://en.wikipedia.org/wiki/D_(programming_language)#Example_1
> It's true that none of these points is really a proof. Still, I'd be
> really happy to hack my own INDEX_FOREACH, but the 500+ LOCs of
> BOOST_FOREACH left me daunted.

This is true, but I'm not convinced. What value BOOST_FOREACH has comes
primarily from its ability to simplify something that's already pretty
darn simple -- a plain for(;;) loop. I strongly resist any effort to
make BOOST_FOREACH more complicated, unless the wins are truly
significant. In this case, I don't think they are.

Nat Goodspeed

unread,
Dec 13, 2009, 8:41:24 PM12/13/09
to boost...@lists.boost.org
Eric Niebler wrote:

>>> Why not:
>>>
>>> int index = 0;
>>>
>>> BOOST_FOREACH(const Foo &f, foos)
>>> {
>>> // ... stuff ...
>>> ++index;
>>> }

> What value BOOST_FOREACH has comes

> primarily from its ability to simplify something that's already pretty
> darn simple -- a plain for(;;) loop. I strongly resist any effort to
> make BOOST_FOREACH more complicated, unless the wins are truly
> significant. In this case, I don't think they are.

Maybe this shouldn't be a BOOST_FOREACH feature at all. As with Python's
builtin enumerate() function, maybe what we want here is an iterator
adapter that dereferences to a std::pair<index_type,
original_iterator_value_type>?

OvermindDL1

unread,
Dec 13, 2009, 9:11:50 PM12/13/09
to boost...@lists.boost.org
On Sun, Dec 13, 2009 at 6:41 PM, Nat Goodspeed <n...@lindenlab.com> wrote:
> Eric Niebler wrote:
>
>>>>    Why not:
>>>>
>>>>     int index = 0;
>>>>
>>>>     BOOST_FOREACH(const Foo &f, foos)
>>>>     {
>>>>       // ... stuff ...
>>>>       ++index;
>>>>     }
>
>> What value BOOST_FOREACH has comes primarily from its ability to simplify
>> something that's already pretty darn simple -- a plain for(;;) loop. I
>> strongly resist any effort to make BOOST_FOREACH more complicated, unless
>> the wins are truly significant. In this case, I don't think they are.
>
> Maybe this shouldn't be a BOOST_FOREACH feature at all. As with Python's
> builtin enumerate() function, maybe what we want here is an iterator adapter
> that dereferences to a std::pair<index_type, original_iterator_value_type>?

Ooo, that makes sense, as long as it can still be done quickly (ala
the in index = 0; example above):
BOOST_FOREACH(size_t i, const Foo &f, ENUMERATE(foos))

Or maybe:
BOOST_FOREACH_ENUMERATE(size_t i, const Foo &f, foos)

OvermindDL1

unread,
Dec 13, 2009, 9:12:48 PM12/13/09
to boost...@lists.boost.org
On Sun, Dec 13, 2009 at 7:11 PM, OvermindDL1 <overm...@gmail.com> wrote:
> On Sun, Dec 13, 2009 at 6:41 PM, Nat Goodspeed <n...@lindenlab.com> wrote:
>> Eric Niebler wrote:
>>
>>>>>    Why not:
>>>>>
>>>>>     int index = 0;
>>>>>
>>>>>     BOOST_FOREACH(const Foo &f, foos)
>>>>>     {
>>>>>       // ... stuff ...
>>>>>       ++index;
>>>>>     }
>>
>>> What value BOOST_FOREACH has comes primarily from its ability to simplify
>>> something that's already pretty darn simple -- a plain for(;;) loop. I
>>> strongly resist any effort to make BOOST_FOREACH more complicated, unless
>>> the wins are truly significant. In this case, I don't think they are.
>>
>> Maybe this shouldn't be a BOOST_FOREACH feature at all. As with Python's
>> builtin enumerate() function, maybe what we want here is an iterator adapter
>> that dereferences to a std::pair<index_type, original_iterator_value_type>?
>
> Ooo, that makes sense, as long as it can still be done quickly (ala
> the in index = 0; example above):
> BOOST_FOREACH(size_t i, const Foo &f, ENUMERATE(foos))
>
> Or maybe:
> BOOST_FOREACH_ENUMERATE(size_t i, const Foo &f, foos)
>

Er, meant my first example to be:
BOOST_FOREACH(tuple<size_t, const Foo&> t, ENUMERATE(foos))

Eric Niebler

unread,
Dec 13, 2009, 9:27:37 PM12/13/09
to boost...@lists.boost.org
Nat Goodspeed wrote:
> Eric Niebler wrote:
>
>>>> Why not:
>>>>
>>>> int index = 0;
>>>>
>>>> BOOST_FOREACH(const Foo &f, foos)
>>>> {
>>>> // ... stuff ...
>>>> ++index;
>>>> }
>
>> What value BOOST_FOREACH has comes primarily from its ability to
>> simplify something that's already pretty darn simple -- a plain
>> for(;;) loop. I strongly resist any effort to make BOOST_FOREACH more
>> complicated, unless the wins are truly significant. In this case, I
>> don't think they are.
>
> Maybe this shouldn't be a BOOST_FOREACH feature at all. As with Python's
> builtin enumerate() function, maybe what we want here is an iterator
> adapter that dereferences to a std::pair<index_type,
> original_iterator_value_type>?

This would fit in well with the proposed resolution of
https://svn.boost.org/trac/boost/ticket/3469. I'll reference this
discussion from that ticket. Thanks for the suggestion.

--
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Daniel James

unread,
Dec 14, 2009, 4:28:03 AM12/14/09
to boost...@lists.boost.org
2009/12/13 The Dude <theds...@gmail.com>:

>
>   It's true that none of these points is really a proof. Still, I'd be
> really happy to hack my own INDEX_FOREACH, but the 500+ LOCs of
> BOOST_FOREACH left me daunted.

It's not that hard:

#define INDEX_FOREACH(index,a,b) \
for(unsigned int index = static_cast<unsigned int>(-1); \
index == static_cast<unsigned int>(-1);) \
BOOST_FOREACH(a,b) if(++index,true)

INDEX_FOREACH(i, const Foo &f, foos)


cout << "The bar of element " << i << " is " << f.bar() << endl;

Mathias Gaunard

unread,
Dec 14, 2009, 4:54:11 AM12/14/09
to boost...@lists.boost.org
The Dude a écrit :

> However, I often need to iterate over a sequence and do some operation
> that depends on both the iterated element and the iteration index. E.g.,
> I would like something like
> <code>
> BOOST_FOREACH(size_t i, const Foo &f, foos)
> cout << "The bar of element " << i << " is " << f.bar() << endl;
> </code>
>
> Is there an easy way to do so?

The index is not something generic enough.
What you would want in the general case is the iterator. But then, you
might as well use the real for loop, since BOOST_FOREACH_IT couldn't be
really less complicated.

Mathias Gaunard

unread,
Dec 14, 2009, 4:59:37 AM12/14/09
to boost...@lists.boost.org
Nat Goodspeed wrote:

> Maybe this shouldn't be a BOOST_FOREACH feature at all. As with Python's
> builtin enumerate() function, maybe what we want here is an iterator
> adapter that dereferences to a std::pair<index_type,
> original_iterator_value_type>?

Couldn't you just do a BOOST_FOREACH over combine(count_range(), foos)
for that?

(uses zip_iterator)

pe...@pcbartlett.com

unread,
Dec 14, 2009, 6:34:14 AM12/14/09
to boost...@lists.boost.org

> Nat Goodspeed wrote:
> > Maybe this shouldn't be a BOOST_FOREACH feature at all. As with
> Python's
> > builtin enumerate() function, maybe what we want here is an
> iterator
> > adapter that dereferences to a std::pair
> original_iterator_value_type>?

> Couldn't you just do a BOOST_FOREACH over combine(count_range(),
> foos)
> for that?
> (uses zip_iterator)

Yup, Nat's idea is a nice one and easy to implement. As Eric alluded to with his reference to the ticket on FOREACH_FIELD, the heart of the matter really though is getting a syntactically convenient version. We've seen this situation - where we have the neat iterators/ranges but not the syntactic convenience - a few times (REVERSE_FOREACH, FOREACH_FIELD, this "FOREACH_WITHINDEX" spring to mind) - I wonder if there is an opportunity to expose a lower level API in the FOREACH mini-library that would enable advanced users to build such macros themselves.

Patrick Horgan

unread,
Dec 15, 2009, 6:22:29 PM12/15/09
to boost...@lists.boost.org
Eric Niebler wrote:
> This is true, but I'm not convinced. What value BOOST_FOREACH has
> comes primarily from its ability to simplify something that's already
> pretty darn simple -- a plain for(;;) loop. I strongly resist any
> effort to make BOOST_FOREACH more complicated, unless the wins are
> truly significant. In this case, I don't think they are.
>
Thanks:) It's one of my pet peeves. How about when someone uses
BOOST_FOREACH when they don't really mean foreach and intend to break
out of the loop and use an internal variable outside the loop. It gets
more complicated then if they'd written their own loop. BOOST_FOREACH
does one thing and does it well, please leave it alone, and please don't
use it when it's not what you want. If you're having to jump through
hoops to make it work, it's not the right tool;) JM2C;)

Patrick

Reply all
Reply to author
Forward
0 new messages