c++boostcollectionsiteratorboost-foreach

Writing back to iterator while looping over more than one collection


I would like to loop through two collections using iterators, modifying one based on a (sufficiently complex) algorithm involving the other. Consider the following minimal example:

#include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
#include <boost/tuple/tuple.hpp> // tie
using namespace std;
using namespace boost;

int main(void) {
  // input data; never mind how these get filled
  int aa[] = {2, 3, 5, 8, 13, 21};
  int bb[] = {1, 0, 1, 1,  0,  1};
  vector<int> a (&aa[0], &aa[sizeof(aa)/sizeof(aa[0])]);
  vector<int> b (&bb[0], &bb[sizeof(bb)/sizeof(bb[0])]);

  // output storage; assume it has always correct dim.
  vector<int> c (a.size());

  // iterate through two coll., reading from both
  int p, q;
  BOOST_FOREACH (tie(p,q), combine(a,b)) { // loop1
    cout << p << "*" << q << "=" << p*q << endl;
  }

  // iterate through one coll., writing to it
  BOOST_FOREACH (int& r, c) { // loop2
    r = 42;
  }

  // iterate through two coll., reading from one, writing to the other?
  BOOST_FOREACH (??? p, s ???, combine(a,c)) { // loop3
    s = p * 2;
  }

  return 0;
}

How do I declare the part between the ???s (or otherwise change the parameters in loop3)?


Solution

  • The value type of a zip_range is a tuple of references to elements:

    #include <iostream>
    #include <vector>
    #include <boost/range.hpp>
    #include <boost/range/combine.hpp>
    #include <boost/tuple/tuple.hpp>
    #include <boost/foreach.hpp>
    
    int main(int ac,char* av[])
    {
      // input data; never mind how these get filled
      int aa[] = {2, 3, 5, 8, 13, 21};
      int bb[] = {1, 0, 1, 1,  0,  1};
      std::vector<int> a(boost::begin(aa), boost::end(aa));
      std::vector<int> const b(boost::begin(bb), boost::end(bb));
    
      // output storage; assume it has always correct dim.
      std::vector<int> c (a.size());
    
      typedef boost::tuple<int const&, int&> val_t;
      BOOST_FOREACH(val_t const& v, boost::combine(a, c)) {
        v.get<1>() = v.get<0>() * 2;
      }
    }