Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
PrevUpHomeNext

Zip Iterator

Example
Reference

The zip iterator provides the ability to parallel-iterate over several controlled sequences simultaneously. A zip iterator is constructed from a tuple of iterators. Moving the zip iterator moves all the iterators in parallel. Dereferencing the zip iterator returns a tuple that contains the results of dereferencing the individual iterators.

The tuple of iterators is now implemented in terms of a Boost fusion sequence. Because of this the 'tuple' may be any Boost fusion sequence and, for backwards compatibility through a Boost fusion sequence adapter, a Boost tuple. Because the 'tuple' may be any boost::fusion sequence the 'tuple' may also be any type for which a Boost fusion adapter exists. This includes, among others, a std::tuple and a std::pair. Just remember to include the appropriate Boost fusion adapter header files for these other Boost fusion adapters. The zip_iterator header file already includes the Boost fusion adapter header file for Boost tuple, so you need not include it yourself to use a Boost tuple as your 'tuple'.

There are two main types of applications of the zip_iterator. The first one concerns runtime efficiency: If one has several controlled sequences of the same length that must be somehow processed, e.g., with the for_each algorithm, then it is more efficient to perform just one parallel-iteration rather than several individual iterations. For an example, assume that vect_of_doubles and vect_of_ints are two vectors of equal length containing doubles and ints, respectively, and consider the following two iterations:

std::vector<double>::const_iterator beg1 = vect_of_doubles.begin();
std::vector<double>::const_iterator end1 = vect_of_doubles.end();
std::vector<int>::const_iterator beg2 = vect_of_ints.begin();
std::vector<int>::const_iterator end2 = vect_of_ints.end();

std::for_each(beg1, end1, func_0());
std::for_each(beg2, end2, func_1());

These two iterations can now be replaced with a single one as follows:

std::for_each(
  boost::make_zip_iterator(
    boost::make_tuple(beg1, beg2)
    ),
  boost::make_zip_iterator(
    boost::make_tuple(end1, end2)
    ),
  zip_func()
  );

A non-generic implementation of zip_func could look as follows:

struct zip_func :
  public std::unary_function<const boost::tuple<const double&, const int&>&, void>
{
  void operator()(const boost::tuple<const double&, const int&>& t) const
  {
    m_f0(t.get<0>());
    m_f1(t.get<1>());
  }

private:
  func_0 m_f0;
  func_1 m_f1;
};

The second important application of the zip_iterator is as a building block to make combining iterators. A combining iterator is an iterator that parallel-iterates over several controlled sequences and, upon dereferencing, returns the result of applying a functor to the values of the sequences at the respective positions. This can now be achieved by using the zip_iterator in conjunction with the transform_iterator.

Suppose, for example, that you have two vectors of doubles, say vect_1 and vect_2, and you need to expose to a client a controlled sequence containing the products of the elements of vect_1 and vect_2. Rather than placing these products in a third vector, you can use a combining iterator that calculates the products on the fly. Let us assume that tuple_multiplies is a functor that works like std::multiplies, except that it takes its two arguments packaged in a tuple. Then the two iterators it_begin and it_end defined below delimit a controlled sequence containing the products of the elements of vect_1 and vect_2:

typedef boost::tuple<
  std::vector<double>::const_iterator,
  std::vector<double>::const_iterator
  > the_iterator_tuple;

typedef boost::zip_iterator<
  the_iterator_tuple
  > the_zip_iterator;

typedef boost::transform_iterator<
  tuple_multiplies<double>,
  the_zip_iterator
  > the_transform_iterator;

the_transform_iterator it_begin(
  the_zip_iterator(
    the_iterator_tuple(
      vect_1.begin(),
      vect_2.begin()
      )
    ),
  tuple_multiplies<double>()
  );

the_transform_iterator it_end(
  the_zip_iterator(
    the_iterator_tuple(
      vect_1.end(),
      vect_2.end()
      )
    ),
  tuple_multiplies<double>()
  );

PrevUpHomeNext