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::vectorstd::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
#include
#include
#include
#include
#include
template< typename Range > struct indexed_range
{
typedef boost::counting_iteratorstd::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(start),
boost::begin(range))),
boost::make_zip_iterator(
boost::make_tuple(
boost::counting_iterator(
boost::distance(range) + start),
boost::end(range))));
}
#include
#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
int main()
{
std::vectorstd::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;
}