Boost logo

Boost Users :

Subject: Re: [Boost-users] foreach question
From: Rob Riggs (rob_at_[hidden])
Date: 2010-10-21 10:45:05


  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;
> }
>

Using c++0x:

     auto myrange = make_iterator_range(
         boost::make_zip_iterator(
             boost::make_tuple(
                 boost::counting_iterator<size_t>(0),
                 result.begin())),
         boost::make_zip_iterator(
             boost::make_tuple(
                 boost::counting_iterator<size_t>(result.size()),
                 result.end())));

     BOOST_FOREACH(auto t, myrange)
     {
         using boost::tuples::get;
         H(row, get<0>(t)) = boost::lexical_cast<int>(get<1>(t));
     }

Which, unfortunately, is quite a bit more verbose and less clear than
what you have now. zip iterators and counting iterators are really nice
concepts, but they don't make for clear, compact code. And just imagine
what that would look like without the type inference provided by c++0x's
"auto" keyword.

However, the making of the zip iterators for this purpose is such a
common idiom in other languages (including Python), and this is easily
abstracted into a helper function, that this would be an ideal
enhancement to Boost.

Something like:

template <typename Range>
auto make_counting_range(Range& range, size_t start = 0) ->
     decltype(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)))))
{
     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))));
}

Which 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.)

Rob


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