Boost logo

Boost Users :

Subject: Re: [Boost-users] foreach question
From: Pete Bartlett (pete_at_[hidden])
Date: 2010-10-21 19:09:32


Rob Riggs wrote:
> On 10/15/2010 12:27 PM, Neal Becker wrote:
>> The following loop iterates over strings in result (which
>> comes from boost::split). Is there a way to include the integer
>> enumerator 'col' into the FOREACH loop?
>>
>> In python that would be spelled
>> for col,s in enumerate (result):
>> ...
>>
>> int col = 0;
>> BOOST_FOREACH (std::string s, result) {
>> H(row, col) = boost::lexical_cast<int> (s);
>> ++col;
>> }
>>
>
>
>Something like:
>
>template <typename Range>
>auto make_counting_range(Range& range, size_t start = 0
>[..]
>
>would then give you:
>
> BOOST_FOREACH(auto t, make_counting_range(result))
> {
> using boost::tuples::get;
> H(row, get<0>(t)) = boost::lexical_cast<int>(get<1>(t));
> }
>
>(Compiled with GCC 4.4.)

Even without C++0x, you can wrap this up into a reasonable interface to get
e.g.

std::vector<std::string> data = boost::assign::list_of("foo")("bar")("baz");
BOOST_INDEXED_EACH( std::size_t i , std::string const& s , data )
        std::cout << "\n" << i << " " << s;

if you tinker a little bit with BOOST_FOREACH internals - see code below,
compiled on vc10 with Boost.ForEach code as in 1.43.
However for the same reasons that BOOST_REVERSE_FOREACH exists (rather than
just using BOOST_FOREACH( ... , make_reverse_range(r) ) - see
http://lists.boost.org/boost-users/2007/07/29101.php ) this approach doesn't
play well with rvalue ranges. Instead you'd have to duplicate the guts of
FOREACH, as Eric did for REVERSE_FOREACH, to get a library-quality version.

Pete

#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/distance.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/iterator/counting_iterator.hpp>

template< typename Range > struct indexed_range
{
  typedef boost::counting_iterator<std::size_t> it0_type;
  typedef typename boost::range_iterator< Range >::type it1_type;
  typedef boost::tuple< it0_type , it1_type > tuple_type;
  typedef boost::zip_iterator< tuple_type > zip_type;
  typedef boost::iterator_range< zip_type > type;
};

template< typename Range >
typename indexed_range<Range>::type
make_indexed_range(Range& range , std::size_t start = 0)
{
       return make_iterator_range(
         boost::make_zip_iterator(
             boost::make_tuple(
                 boost::counting_iterator<size_t>(start),
                 boost::begin(range))),
         boost::make_zip_iterator(
             boost::make_tuple(
                 boost::counting_iterator<size_t>(
                     boost::distance(range) + start),
                 boost::end(range))));
}

#include <boost/foreach.hpp>

#define BOOST_INDEXED_EACH_IMPL(VAR1, VAR2 , 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_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 \
        for (VAR1 = boost::tuples::get<0>( BOOST_FOREACH_DEREF(COL) );
!BOOST_FOREACH_ID(_foreach_continue);)\
          for(VAR2 = boost::tuples::get<1>( BOOST_FOREACH_DEREF(COL) );
!BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) =
true)

#define BOOST_INDEXED_EACH(VAR1,VAR2,COL)
BOOST_INDEXED_EACH_IMPL(VAR1,VAR2,make_indexed_range(COL))

//test scaffolding
#include <vector>
#include <iostream>
#include <boost/assign/list_of.hpp>

int main()
{
  std::vector<std::string> data =
boost::assign::list_of("foo")("bar")("baz");
  BOOST_INDEXED_EACH( std::size_t i , std::string s , data )
    std::cout << "\n" << i << " " << s;

  std::cout << "\n\n";
  return 0;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net