Home | Libraries | People | FAQ | More |
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 = ...; boost::sort(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
boost:unique(boost::sort(vec));
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
boost::copy(boost::unique(boost::sort(vec)), std::ostream_iterator<int>(std::cout));
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:
Expression |
Return |
---|---|
|
returns a single iterator like |
|
returns the range |
|
returns the range |
|
returns the range |
|
returns the range |
|
returns the entire original range. |
This functionality has the following advantages:
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()) ++i; 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.