The Boost C++ Libraries

Algorithms

You can think of a range as two iterators that refer to the beginning and end of a group of elements that you can iterate over. Because all containers support iterators, every container can be thought of as a range. Since all algorithms from Boost.Range expect a range as a first parameter, a container like std::vector can be passed directly. You don’t have to call begin() and end() and then pass two iterators separately. This protects you from mistakes such as passing the begin and end iterator in the wrong order or passing iterators that belong to two different containers.

Example 30.1. Counting with boost::count()
#include <boost/range/algorithm.hpp>
#include <array>
#include <iostream>

int main()
{
  std::array<int, 6> a{{0, 1, 0, 1, 0, 1}};
  std::cout << boost::count(a, 0) << '\n';
}

Example 30.1 uses the algorithm boost::count(), which is defined in boost/range/algorithm.hpp. This header file provides access to all of the algorithms for which counterparts exist in the standard library header file algorithm.

All algorithms from Boost.Range require the first parameter to be a range. An object of type std::array can be passed to boost::count() directly since containers are ranges. Because boost::count() is equivalent to std::count(), you must pass in the value that the elements in the range will be compared with.

In Example 30.1, a contains three zeros, so 3 is written to standard output.

Example 30.2 introduces more algorithms which, like boost::count(), are similar to algorithms from the standard library.

Example 30.2. Range algorithms related to algorithms from the standard library
#include <boost/range/algorithm.hpp>
#include <boost/range/numeric.hpp>
#include <array>
#include <iterator>
#include <iostream>

int main()
{
  std::array<int, 6> a{{0, 1, 2, 3, 4, 5}};
  boost::random_shuffle(a);
  boost::copy(a, std::ostream_iterator<int>{std::cout, ","});
  std::cout << "\n" << *boost::max_element(a) << '\n';
  std::cout << boost::accumulate(a, 0) << '\n';
}

boost::random_shuffle() works like std::random_shuffle(), changing the order of elements in a range randomly. Example 30.2 uses boost::random_shuffle() with a default random number generator. However, you can pass a random number generator as a second parameter. That can be a random number generator either from the C++11 header file random or from Boost.Random.

boost::copy() works like std::copy(). boost::max_element() and boost::accumulate() work like the identically named algorithms from the standard library. Like std::max_element(), boost::max_element() returns an iterator to the element with the greatest number.

The header file boost/range/numeric.hpp must be included for boost::accumulate(). Just as std::accumulate() is defined in numeric, boost::accumulate() is defined in boost/range/numeric.hpp and not in boost/range/algorithm.hpp.

Boost.Range also provides a few algorithms without counterparts in the standard library.

Example 30.3. Range algorithms without counterparts in the standard library
#include <boost/range/algorithm_ext.hpp>
#include <array>
#include <deque>
#include <iterator>
#include <iostream>

int main()
{
  std::array<int, 6> a{{0, 1, 2, 3, 4, 5}};
  std::cout << std::boolalpha << boost::is_sorted(a) << '\n';
  std::deque<int> d;
  boost::push_back(d, a);
  boost::remove_erase(d, 2);
  boost::copy_n(d, 3, std::ostream_iterator<int>{std::cout, ","});
}

The algorithms used in Example 30.3 require the header file boost/range/algorithm_ext.hpp. This header file provides access to algorithms that have no counterpart in the standard library.

boost::is_sorted() tests whether elements in a range are sorted. In Example 30.3, boost::is_sorted() returns true because a is sorted. A predicate can be passed as the second parameter to boost::is_sorted() to check, for example, whether a range is sorted in descending order.

boost::push_back() expects as its first parameter a container and as its second parameter a range. The container must define the member function push_back(). All elements from the range are added to the container using this member function, in the order specified by the range. Because d starts out empty, it will contain the same numbers as a, in the same order, after the call to boost::push_back().

boost::remove_erase() removes the number 2 from d. This algorithm combines a call to the function std::remove() and a call to the member function erase() of the respective container. Thanks to boost::remove_erase(), you don’t need to find the iterator to the element you need to remove and then pass it to erase() in a second step.

boost::copy_n() is similar to boost::copy(), but copies only as many elements as the number passed as its second parameter. Example 30.3 only writes the first three numbers from d to standard output. Because 2 was removed from d in the previous line, 0,1,3, is displayed.