Article Discussion
Conditional Love: FOREACH Redux
Summary: Plowing through some devilish details of template argument deduction, the conditional operator and the macro preprocessor, Eric develops a robust FOR_EACH iterator. Whether you're using arrays, strings, or containers, this one does it all.
8 posts on 1 page.      
« Previous 1 Next »
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: April 2, 2005 7:59 AM by Eric
Chuck
Posts: 32 / Nickname: cda / Registered: February 11, 2003 0:06 PM
Conditional Love: FOREACH Redux
February 18, 2005 3:00 AM      
Eric Niebler shows how to use the subtleties of the conditional operator, coupled with templates and macro magic, to create a robust iteration construct.

http://www.artima.com/cppsource/foreach.html
Bruno
Posts: 2 / Nickname: br1 / Registered: November 7, 2003 2:50 PM
Re: Conditional Love: FOREACH Redux
February 18, 2005 3:00 AM      
I really had a great time reading this article. I just loved the cleverness of using the ternary operator to get the type and pass it to auto_any functions. This is one of those articles that just amaze you, because you already knew how the parts work but it would never have ocurred you to combine them.

The part about rvalue detection isn't that great, though, as the you knew it part doesn't exist.
indranil
Posts: 8 / Nickname: indranil / Registered: November 7, 2004 8:29 AM
Re: Conditional Love: FOREACH Redux
February 18, 2005 10:08 AM      
Awesome article, FOREACH is the kind of utility that can massively improve the quality of C++ code and it is amazing to see how it is implemented.

I decided to delve deeper and looked at foreach.hpp. I noticed a number of difference from the article, I guess these were mainly for exposition purposes.

BOOST_FOREACH doesnt use boost::variant, it has a mini roll-your-own simple_variant class, any reason why? Also simple_variant doesnt have an assignment operator, i guess the default implementation is safe here.

Things like rvalue_probe and auto_any could be useful in other contexts, are they used elsewhere in Boost or the wider world? If so should they be factored out into their own headers?

Finally is it safe to nest two BOOST_FOREACH macros?
Eric
Posts: 12 / Nickname: ericne / Registered: February 18, 2005 5:31 AM
Re: Conditional Love: FOREACH Redux
February 18, 2005 10:40 AM      
> Awesome article

Thanks!

> BOOST_FOREACH doesnt use boost::variant, it has a mini
> roll-your-own simple_variant class, any reason why?

I found it was hurting compile times. It's a bigger hammer than I really need in this case.

> Also simple_variant doesnt have an assignment operator,
> i guess the default implementation is safe here.

It's not! But I never assign one of these guys. I should make the assignment operator private, thanks!

> Things like rvalue_probe and auto_any could be useful
> in other contexts, are they used elsewhere in Boost or
> the wider world? If so should they be factored out into
> their own headers?

I'll factor them out as need requires.

> Finally is it safe to nest two BOOST_FOREACH macros?

You bet!

--
Eric Niebler
Boost Consulting
www.boost-consulting.com
Eric
Posts: 12 / Nickname: ericne / Registered: February 18, 2005 5:31 AM
Re: Conditional Love: FOREACH Redux
February 21, 2005 10:52 AM      
Incidentally, I have found a simpler formulation of ENCODED_TYPEOF that doesn't require type2type or anytype. Consider:

template<class T>
T const * encode_type( T const & t ) {
return 0;
}

#define ENCODED_TYPEOF( expr )\
( true ? 0 : encode_type( expr ) )

This uses the fact that the null pointer constant (0) is implicitly convertible to a pointer of any type. Now, you can use "T const*" as a dummy parameter to functions that need to infer the type T. Not only is this simpler, but it even works on ancient compilers like VC6.

Also, Andrei Alexandrescu has sent me a "perfect" version of the MIN/MAX macros that use the conditional operator trick to avoid reevaluation of their arguments. Very neat stuff! We'll hopefully be posting it soon.

--
Eric Niebler
Boost Consulting
www.boost-consulting.com
martin
Posts: 1 / Nickname: mjcohen / Registered: October 13, 2003 11:38 AM
Re: Conditional Love: FOREACH Redux
February 23, 2005 11:50 AM      
Whew! A lot of nice stuff - I'll have to reread this a few times.

I personally love the conditional operator, and use it a lot in both C and gawk. My "secret" to making nested conditionals understandable is to treat it as being precisely analogous to nested if-then-else statements. An example is


a = (b > 0
? (c/2)
: (g in hoohaa
? (int(h) == h
? (cos(r) <= sin(r)
? tanh(e)
: lngamma(pi)
)
: (2/zeta(e))
)
: (g-1)
)
);


(Hope everything is lined up and balanced - Emacs helps a lot)
Liu
Posts: 4 / Nickname: pongba / Registered: March 6, 2005 11:46 PM
Re: Conditional Love: FOREACH Redux
March 23, 2005 8:50 PM      
Despite of my absolute loving this facility,I wonder if there exists one little pitfall.

It seems to me that the problem raises its ugly head when we use BOOST_FOREACH for some container that contains instances of type like std::string or whatever owns its own resource.

IMO,some classes that hold their own resources will do copy assignment differently as they do "destruction-then-in-place-construction".

Since BOOST_FOREACH uses nested for-statement,the variable in the inner loop will get initialized each time the outer for-loop recurs.Note that I refered to "initialize" instead of "copy-assignment",the former means a destruction followed by a construction,while the latter means merely one copy assignment.

For me,the situation can become really tough when the class gets a optimized copy assignment which can reuse the previously allocated storage to hold the new stuffs,while its destructor *delete* the storage and its constructor *re-require* them.

e.g.

for(string s = ...;...;...)
{
s = ...; // copy assignment , the lifetime of s lasts until the for-statement ends
}

// BOOST_FOREACH's implementation
for(...)
{
for(string s = ...;...;...) // get re-constructed each time the outer loop recurs
{
}
}

Surely,I know that there should be some caveat when using BOOST_FOREACH,one of which should refer to this.But I read through the document and see nothing about that,so I wonder if it's an oversight,or "not-a-problem",or merely my misunderstand?

Anyway,thank you for doing such an excellent job,it's really usefull and amazing.
Eric
Posts: 12 / Nickname: ericne / Registered: February 18, 2005 5:31 AM
Re: Conditional Love: FOREACH Redux
April 2, 2005 7:59 AM      
liu wei peng, you are correct, there are scenarios where BOOST_FOREACH could cause an extra allocation over a hand-coded loop. Funny, that hadn't even occured to me. I don't see a way to fix it while allowing BOOST_FOREACH to continue working with references, because the reference simply must be rebound each time:


for(..;..;..)
for(int &i = ..;..;..)


This is certainly a trade-off, though, and I see your point. You can avoid the construction/destruction issue if you use BOOST_FOREACH like this:


std:::string str;
BOOST_FOREACH(str, vector_of_string)
..


There should probably be a note about this in BOOST_FOREACH's documentation.

Thanks for raising the issue.

--
Eric Niebler
Boost Consulting
www.boost-consulting.com
8 posts on 1 page.
« Previous 1 Next »