7.4. Writing Your Own View
Since most of a sequence view's smarts are in its iterators, it stands to reason that most of the work of implementing a view involves implementing an iterator adaptor. Let's whip up an iterator for zip_view to see how it's done.
Since zip_view operates on a sequence of input sequences, it's natural that its iterator should operate on a sequence of iterators into those input sequences. Let's give our zip_iterator an iterator sequence parameter:
template <class IteratorSeq>
struct zip_iterator;
The MPL's zip_iterator models the least refined concept of any of its component iterators, but for the sake of simplicity our zip_iterator will always be a forward iterator. The only requirements we need to satisfy for a forward iterator are dereferencing with mpl::deref and incrementing with mpl::next. To dereference a zip iterator we need to dereference each of its component iterators and pack the results into a sequence. Taking advantage of the default definition of mpl::deref, which just invokes its argument as a metafunction, the body of zip_iterator is defined thus:
template <class IteratorSeq>
struct zip_iterator
{
typedef mpl::forward_iterator_tag category;
typedef typename mpl::transform<
IteratorSeq
, mpl::deref<_1>
>::type type;
};
Similarly, to increment a zip iterator we need to increment each of its component iterators:
namespace boost { namespace mpl
{
// specialize next<...> for zip_iterator
template <class IteratorSeq>
struct next<::zip_iterator<IteratorSeq> >
{
typedef ::zip_iterator<
typename transform<
IteratorSeq
, next<_1>
>::type
> type;
};
}}
The one remaining element we might want to add to the body of zip_iterator, as a convenience, is a ::base member that accesses the iterators being adapted. In an iterator adaptor for a single iterator, ::base would just be that one iterator; in this case, though, it will be a sequence of underlying iterators:
template <class IteratorSeq>
struct zip_iterator
{
typedef IteratorSeq base;
...
};
Now there's almost nothing left to do for zip_view; it's just a sequence that uses zip_iterator. In fact, we can build zip_view out of iterator_range:
template <class Sequences>
struct zip_view
: mpl::iterator_range<
zip_iterator<
typename mpl::transform_view<
Sequences, mpl::begin<_1>
>::type
>
, zip_iterator<
typename mpl::transform_view<
Sequences, mpl::end<_1>
>::type
>
>
{};
 |