Boost C++ Libraries Home Libraries People FAQ More


Introduction and motivation

In its most simple form a Range Algorithm (or range-based algorithm) is simply an iterator-based algorithm where the two iterator arguments have been replaced by one range argument. For example, we may write

#include <boost/range/algorithm.hpp>
#include <vector>

std::vector<int> vec = ...;

instead of

std::sort(vec.begin(), vec.end());

However, the return type of range algorithms is almost always different from that of existing iterator-based algorithms.

One group of algorithms, like boost::sort(), will simply return the same range so that we can continue to pass the range around and/or further modify it. Because of this we may write


to first sort the range and then run unique() on the sorted range.

Algorithms like boost::unique() fall into another group of algorithms that return (potentially) narrowed views of the original range. By default boost::unique(rng) returns the range [boost::begin(rng), found) where found denotes the iterator returned by std::unique(boost::begin(rng), boost::end(rng))

Therefore exactly the unique values can be copied by writing


Algorithms like boost::unique usually return the same range: [boost::begin(rng), found). However, this behaviour may be changed by supplying the algorithms with a template argument:




returns a single iterator like std::unique


returns the range [boost::begin(rng), found) (this is the default)


returns the range [boost::begin(rng), boost::next(found))


returns the range [found, boost::end(rng))


returns the range [boost::next(found),boost::end(rng))


returns the entire original range.

This functionality has the following advantages:

  1. it allows for seamless functional-style programming where you do not need to use named local variables to store intermediate results
  2. it is very safe because the algorithm can verify out-of-bounds conditions and handle tricky conditions that lead to empty ranges

For example, consider how easy we may erase the duplicates in a sorted container:

std::vector<int> vec = ...;
boost::erase(vec, boost::unique<boost::return_found_end>(boost::sort(vec)));

Notice the use of boost::return_found_end. What if we wanted to erase all the duplicates except one of them? In old-fashined STL-programming we might write

// assume 'vec' is already sorted
std::vector<int>::iterator i = std::unique(vec.begin(), vec.end());

// remember this check or you get into problems
if (i != vec.end())

vec.erase(i, vec.end());

The same task may be accomplished simply with

boost::erase(vec, boost::unique<boost::return_next_end>(vec));

and there is no need to worry about generating an invalid range. Furthermore, if the container is complex, calling vec.end() several times will be more expensive than using a range algorithm.