
Sorry I've taken a little while to respond, I don't really have the energy to code during the week. 2009/9/14 Pete Bartlett <pete@pcbartlett.com>:
Mathias Gaunard wrote: Chris Purcell wrote:
As documented in the manual ("Pitfalls"), BOOST_FOREACH is a little awkward to use with associative containers.
I think your BOOST_FOREACH_PAIR is interesting, but maybe it could be generalized to tuples?
It could. Pitfalls to avoid if possible are - ugly syntax of one macro per arity - parenthesis soup so common to PP-programming.
I think maybe
BOOST_FOREACH_TUPLE( (Arg1T)(arg1) .... (ArgNT)(argn) , range )
could be made to work.
This is a great idea. After a pointer in the right direction from Dan Marsden, I've generalized the macro to Boost.Fusion-compatible types. The syntax is as follows: std::map<int, int> my_map; BOOST_FOREACH_FIELD((int key)(int value), my_map) std::cout << key << " : " << value << "\n"; std::vector<boost::fusion::vector<int, std::string, int> > my_complex_type; BOOST_FOREACH_FIELD((int i)(std::string const& j)(int& k), my_complex_type) std::cout << "line: " << i << ", " << j << ", " << ++k; I think this is probably the least number of brackets possible without a macro per permutation. To get it working, I need a Boost.Preprocessor header and two Boost.Fusion headers: #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/fusion/include/at_c.hpp> #include <boost/fusion/include/std_pair.hpp> I need a single macro to do per-field assignment: #define BOOST_FOREACH_ASSIGN_VAR(R, ROW, I, VAR) for (VAR = boost::fusion::at_c<I>(ROW); !BOOST_FOREACH_ID(_foreach_leave_outerloop); BOOST_FOREACH_ID(_foreach_leave_outerloop) = true) And now the macro is once again a small modification of the existing BOOST_FOREACH macro: #define BOOST_FOREACH_FIELD(VARS, COL) BOOST_FOREACH_PREAMBLE() if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL)) {} else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_END(COL)) {} else for (bool BOOST_FOREACH_ID(_foreach_continue) = true, BOOST_FOREACH_ID(_foreach_leave_outerloop) = true; BOOST_FOREACH_ID(_foreach_continue) && !BOOST_FOREACH_DONE(COL); BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_NEXT(COL) : (void)0) if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue))) {} else if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_leave_outerloop))) {} else BOOST_PP_SEQ_FOR_EACH_I(BOOST_FOREACH_ASSIGN_VAR, BOOST_FOREACH_DEREF(COL), VARS) for (; !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true) Once again, this is for the 1.40.0 release of boost, and any line breaks in the #defines have been added en-route. Cheers, Chris