How would you fill up a vector with the numbers zero through one hundred using std::copy()? The only iterator operation missing from builtin integer types is an operator*() that returns the current value of the integer. The counting iterator adaptor adds this crucial piece of functionality to whatever type it wraps. One can use the counting iterator adaptor not only with integer types, but with any type that is Incrementable (see type requirements below). The following pseudo-code shows the general idea of how the counting iterator is implemented.
// inside a hypothetical counting_iterator class... typedef Incrementable value_type; value_type counting_iterator::operator*() const { return this->base; // no dereference! }All of the other operators of the counting iterator behave in the same fashion as the Incrementable base type.
namespace boost { template <class Incrementable> struct counting_iterator_traits; template <class Incrementable> struct counting_iterator_generator; template <class Incrementable> typename counting_iterator_generator<Incrementable>::type make_counting_iterator(Incrementable x); }
template <class Incrementable> class counting_iterator_generator { public: typedef iterator_adaptor<...> type; };
#include <boost/config.hpp> #include <iostream> #include <boost/counting_iterator.hpp> int main(int, char*[]) { // Example of using counting_iterator_generator std::cout << "counting from 0 to 4:" << std::endl; boost::counting_iterator_generator<int>::type first(0), last(4); std::copy(first, last, std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; // to be continued...The output from this part is:
counting from 0 to 4: 0 1 2 3
Parameter | Description |
---|---|
Incrementable | The type being wrapped by the adaptor. |
Furthermore, if you wish to create a counting iterator that is a Forward Iterator, then the following expressions must be valid:
Incrementable i, j; ++i // pre-increment i == j // operator equalIf you wish to create a counting iterator that is a Bidirectional Iterator, then pre-decrement is also required:
--iIf you wish to create a counting iterator that is a Random Access Iterator, then these additional expressions are also required:
counting_iterator_traits<Incrementable>::difference_type n; i += n n = i - j i < j
counting_iterator_generator::type(const Incrementable& i)
template <class Incrementable> typename counting_iterator_generator<Incrementable>::type make_counting_iterator(Incrementable base);An object generator function that provides a convenient way to create counting iterators.
// continuing from previous example... std::cout << "counting from -5 to 4:" << std::endl; std::copy(boost::make_counting_iterator(-5), boost::make_counting_iterator(5), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl; // to be continued...The output from this part is:
counting from -5 to 4: -5 -4 -3 -2 -1 0 1 2 3 4In the next example we create an array of numbers, and then create a second array of pointers, where each pointer is the address of a number in the first array. The counting iterator makes it easy to do this since dereferencing a counting iterator that is wrapping an iterator over the array of numbers just returns a pointer to the current location in the array. We then use the indirect iterator adaptor to print out the number in the array by accessing the numbers through the array of pointers.
// continuing from previous example... const int N = 7; std::vector<int> numbers; // Fill "numbers" array with [0,N) std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N), std::back_inserter(numbers)); std::vector<std::vector<int>::iterator> pointers; // Use counting iterator to fill in the array of pointers. std::copy(boost::make_counting_iterator(numbers.begin()), boost::make_counting_iterator(numbers.end()), std::back_inserter(pointers)); // Use indirect iterator to print out numbers by accessing // them through the array of pointers. std::cout << "indirectly printing out the numbers from 0 to " << N << std::endl; std::copy(boost::make_indirect_iterator(pointers.begin()), boost::make_indirect_iterator(pointers.end()), std::ostream_iterator<int>(std::cout, " ")); std::cout << std::endl;The output is:
indirectly printing out the numbers from 0 to 7 0 1 2 3 4 5 6
The following pseudocode describes how the counting_iterator_traits are determined:
template <class Incrementable> struct counting_iterator_traits { if (numeric_limits<Incrementable>::is_specialized) { if (!numeric_limits<Incrementable>::is_integer) COMPILE_TIME_ERROR; if (!numeric_limits<Incrementable>::is_bounded && numeric_limits<Incrementable>::is_signed) { typedef Incrementable difference_type; } else if (numeric_limits<Incrementable>::is_integral) { typedef next-larger-signed-type-or-intmax_t difference_type; } typedef std::random_access_iterator_tag iterator_category; } else { typedef std::iterator_traits<Incrementable>::difference_type difference_type; typedef std::iterator_traits<Incrementable>::iterator_category iterator_category; } };
The italicized sections above are implementation details, but it is important to know that the difference_type for integral types is selected so that it can always represent the difference between two values if such a built-in integer exists. On platforms with a working std::numeric_limits implementation, the difference_type for any variable-length signed integer type T is T itself.
Revised 19 Aug 2001
© Copyright Jeremy Siek 2000. 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.