Boost logo

Boost :

Subject: Re: [boost] [Foreach] Proposal to simplify using Boost.Foreach withmaps
From: Chris Purcell (chris.purcell.39_at_[hidden])
Date: 2009-09-19 08:26:33


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_at_[hidden]>:
>>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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk