c++boost.gif (8819 bytes)

Counting Iterator Adaptor

Defined in header boost/counting_iterator.hpp

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.

Synopsis

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

The Counting Iterator Type Generator

The class template counting_iterator_generator<Incrementable> is a type generator for counting iterators.
template <class Incrementable>
class counting_iterator_generator
{
public:
    typedef iterator_adaptor<...> type;
};

Example

In this example we use the counting iterator generator to create a counting iterator, and count from zero to four.
#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 

Template Parameters

ParameterDescription
Incrementable The type being wrapped by the adaptor.

Model of

If the Incrementable type has all of the functionality of a Random Access Iterator except the operator*(), then the counting iterator will be a model of Random Access Iterator. If the Incrementable type has less functionality, then the counting iterator will have correspondingly less functionality.

Type Requirements

The Incrementable type must be Default Constructible, Copy Constructible, and Assignable. Also, the Incrementable type must provide access to an associated difference_type and iterator_category through the counting_iterator_traits class.

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 equal
If you wish to create a counting iterator that is a Bidirectional Iterator, then pre-decrement is also required:
--i
If 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

Members

The counting iterator type implements the member functions and operators required of the Random Access Iterator concept. In addition it has the following constructor:
counting_iterator_generator::type(const Incrementable& i)


The Counting Iterator Object Generator

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.

Example

In this example we count from negative five to positive five, this time using the make_counting_iterator() function to save some typing.
  // 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 4 
In 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 

Counting Iterator Traits

The counting iterator adaptor needs to determine the appropriate difference_type and iterator_category to use based on the Incrementable type supplied by the user. The counting_iterator_traits class provides these types. If the Incrementable type is an integral type or an iterator, these types will be correctly deduced by the counting_iterator_traits provided by the library. Otherwise, the user must specialize counting_iterator_traits for her type or add nested typedefs to her type to fulfill the needs of std::iterator_traits.

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.