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>()
  );

Synopsis

template<typename IteratorTuple>
class zip_iterator
{

public:
  typedef /* see below */ reference;
  typedef reference value_type;
  typedef value_type* pointer;
  typedef /* see below */ difference_type;
  typedef /* see below */ iterator_category;

  zip_iterator();
  zip_iterator(IteratorTuple iterator_tuple);

  template<typename OtherIteratorTuple>
  zip_iterator(
        const zip_iterator<OtherIteratorTuple>& other
      , typename enable_if_convertible<
              OtherIteratorTuple
            , IteratorTuple>::type* = 0     // exposition only
  );

  const IteratorTuple& get_iterator_tuple() const;

private:
  IteratorTuple m_iterator_tuple;     // exposition only
};

template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t);

The reference member of zip_iterator is the type of the tuple made of the reference types of the iterator types in the IteratorTuple argument.

The difference_type member of zip_iterator is the difference_type of the first of the iterator types in the IteratorTuple argument.

The iterator_category member of zip_iterator is convertible to the minimum of the traversal categories of the iterator types in the IteratorTuple argument. For example, if the zip_iterator holds only vector iterators, then iterator_category is convertible to boost::random_access_traversal_tag. If you add a list iterator, then iterator_category will be convertible to boost::bidirectional_traversal_tag, but no longer to boost::random_access_traversal_tag.

Requirements

All iterator types in the argument IteratorTuple shall model Readable Iterator.

Concepts

The resulting zip_iterator models Readable Iterator.

The fact that the zip_iterator models only Readable Iterator does not prevent you from modifying the values that the individual iterators point to. The tuple returned by the zip_iterator's operator* is a tuple constructed from the reference types of the individual iterators, not their value types. For example, if zip_it is a zip_iterator whose first member iterator is an std::vector<double>::iterator, then the following line will modify the value which the first member iterator of zip_it currently points to:

zip_it->get<0>() = 42.0;

Consider the set of standard traversal concepts obtained by taking the most refined standard traversal concept modeled by each individual iterator type in the IteratorTuple argument.The zip_iterator models the least refined standard traversal concept in this set.

zip_iterator<IteratorTuple1> is interoperable with zip_iterator<IteratorTuple2> if and only if IteratorTuple1 is interoperable with IteratorTuple2.

Operations

In addition to the operations required by the concepts modeled by zip_iterator, zip_iterator provides the following operations.

zip_iterator();

Returns: An instance of zip_iterator with m_iterator_tuple default constructed.

zip_iterator(IteratorTuple iterator_tuple);

Returns: An instance of zip_iterator with m_iterator_tuple initialized to iterator_tuple.

template<typename OtherIteratorTuple>
zip_iterator(
      const zip_iterator<OtherIteratorTuple>& other
    , typename enable_if_convertible<
            OtherIteratorTuple
          , IteratorTuple>::type* = 0     // exposition only
);

Returns: An instance of zip_iterator that is a copy of other.
Requires: OtherIteratorTuple is implicitly convertible to IteratorTuple.

const IteratorTuple& get_iterator_tuple() const;

Returns: m_iterator_tuple

reference operator*() const;

Returns: A tuple consisting of the results of dereferencing all iterators in m_iterator_tuple.

zip_iterator& operator++();

Effects: Increments each iterator in m_iterator_tuple.
Returns: *this

zip_iterator& operator--();

Effects: Decrements each iterator in m_iterator_tuple.
Returns: *this

template<typename IteratorTuple>
zip_iterator<IteratorTuple>
make_zip_iterator(IteratorTuple t);

Returns: An instance of zip_iterator<IteratorTuple> with m_iterator_tuple initialized to t.


PrevUpHomeNext