The indirect iterator adaptor augments an iterator by applying an extra dereference inside of operator*(). For example, this iterator makes it possible to view a container of pointers or smart-pointers (e.g. std::list<boost::shared_ptr<foo> >) as if it were a container of the pointed-to type. The following pseudo-code shows the basic idea of the indirect iterator:
// inside a hypothetical indirect_iterator class... typedef std::iterator_traits<BaseIterator>::value_type Pointer; typedef std::iterator_traits<Pointer>::reference reference; reference indirect_iterator::operator*() const { return **this->base_iterator; }
namespace boost { template <class BaseIterator, class Value, class Reference, class Category, class Pointer> struct indirect_iterator_generator; template <class BaseIterator, class Value, class Reference, class ConstReference, class Category, class Pointer, class ConstPointer> struct indirect_iterator_pair_generator; template <class BaseIterator> typename indirect_iterator_generator<BaseIterator>::type make_indirect_iterator(BaseIterator base) }
template <class BaseIterator, class Value, class Reference, class Pointer> class indirect_iterator_generator { public: typedef iterator_adaptor<...> type; // the resulting indirect iterator type };
#include <boost/config.hpp> #include <vector> #include <iostream> #include <iterator> #include <boost/iterator_adaptors.hpp> int main(int, char*[]) { char characters[] = "abcdefg"; const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char char* pointers_to_chars[N]; // at the end. for (int i = 0; i < N; ++i) pointers_to_chars[i] = &characters[i]; boost::indirect_iterator_generator<char**, char>::type indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N); std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ",")); std::cout << std::endl; // to be continued...
Parameter | Description |
---|---|
BaseIterator | The iterator type being wrapped. The value_type of the base iterator should itself be dereferenceable. The return type of the operator* for the value_type should match the Reference type. |
Value | The value_type of the resulting iterator, unless const. If
Value is const X, a conforming compiler makes the
value_type non-const X[1]. Note that if the default
is used for Value, then there must be a valid specialization
of iterator_traits for the value type of the base iterator.
Default: std::iterator_traits< std::iterator_traits<BaseIterator>::value_type >::value_type[2] |
Reference | The reference type of the resulting iterator, and in
particular, the result type of operator*(). Default: Value& |
Pointer | The pointer type of the resulting iterator, and in
particular, the result type of operator->(). Default: Value* |
Category | The iterator_category type for the resulting iterator. Default: std::iterator_traits<BaseIterator>::iterator_category |
explicit indirect_iterator_generator::type(const BaseIterator& it)
template <class BaseIterator, class Value, class Pointer, class Reference, class ConstPointer, class ConstReference> class indirect_iterator_pair_generator { public: typedef iterator_adaptor<...> iterator; // the mutable indirect iterator type typedef iterator_adaptor<...> const_iterator; // the immutable indirect iterator type };
// continuing from the last example... typedef boost::indirect_iterator_pair_generator<char**, char, char*, char&, const char*, const char&> PairGen; char mutable_characters[N]; char* pointers_to_mutable_chars[N]; for (int i = 0; i < N; ++i) pointers_to_mutable_chars[i] = &mutable_characters[i]; PairGen::iterator mutable_indirect_first(pointers_to_mutable_chars), mutable_indirect_last(pointers_to_mutable_chars + N); PairGen::const_iterator const_indirect_first(pointers_to_chars), const_indirect_last(pointers_to_chars + N); std::transform(const_indirect_first, const_indirect_last, mutable_indirect_first, std::bind1st(std::plus<char>(), 1)); std::copy(mutable_indirect_first, mutable_indirect_last, std::ostream_iterator<char>(std::cout, ",")); std::cout << std::endl; // to be continued...
The output is:
b,c,d,e,f,g,h,
Parameter | Description |
---|---|
BaseIterator | The iterator type being wrapped. The value_type of the base iterator should itself be dereferenceable. The return type of the operator* for the value_type should match the Reference type. |
Value | The value_type of the resulting iterators.
If Value is const X, a conforming compiler makes the
value_type non-const X[1]. Note that if the default
is used for Value, then there must be a valid
specialization of iterator_traits for the value type
of the base iterator. Default: std::iterator_traits< std::iterator_traits<BaseIterator>::value_type >::value_type[2] |
Reference | The reference type of the resulting iterator, and
in particular, the result type of its operator*(). Default: Value& |
Pointer | The pointer type of the resulting iterator, and
in particular, the result type of its operator->(). Default: Value* |
ConstReference | The reference type of the resulting
const_iterator, and in particular, the result type of its
operator*(). Default: const Value& |
ConstPointer | The pointer type of the resulting const_iterator,
and in particular, the result type of its operator->(). Default: const Value* |
Category | The iterator_category type for the resulting iterator. Default: std::iterator_traits<BaseIterator>::iterator_category |
explicit indirect_iterator_pair_generator::iterator(const BaseIterator& it) explicit indirect_iterator_pair_generator::const_iterator(const BaseIterator& it)
template <class BaseIterator> typename indirect_iterator_generator<BaseIterator>::type make_indirect_iterator(BaseIterator base)
The output is:// continuing from the last example... std::copy(boost::make_indirect_iterator(pointers_to_chars), boost::make_indirect_iterator(pointers_to_chars + N), std::ostream_iterator<char>(std::cout, ",")); std::cout << std::endl; return 0; }
a,b,c,d,e,f,g,
[2] If your compiler does not support partial specialization and the base iterator or its value_type is a builtin pointer type, you will not be able to use the default for Value and will need to specify this type explicitly.
[3]There is a caveat to which concept the indirect iterator can model. If the return type of the operator* for the base iterator's value type is not a true reference, then strickly speaking, the indirect iterator can not be a model of Forward Iterator or any of the concepts that refine it. In this case the Category for the indirect iterator should be specified as std::input_iterator_tag. However, even in this case, if the base iterator is a random access iterator, the resulting indirect iterator will still satisfy most of the requirements for Random Access Iterator.
Revised 17 Aug 2001
© Copyright Jeremy Siek and David Abrahams 2001. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.