The algorithms and adaptors provided by Boost.Range are based on templates. You don’t have to transform a container to a range to pass it to an algorithm or adaptor. However, Boost.Range defines a few range classes, with boost::iterator_range
being the most important. boost::iterator_range
is required because adaptors and a few algorithms return ranges that must have a type. In addition, helper functions exist that create ranges whose iterators contain all the data required for an iteration. The iterators from these ranges don’t refer to a container or to another data structure. A class like boost::iterator_range
is used here, too.
boost::irange()
#include <boost/range/algorithm.hpp>
#include <boost/range/irange.hpp>
#include <iostream>
int main()
{
boost::integer_range<int> ir = boost::irange(0, 3);
boost::copy(ir, std::ostream_iterator<int>{std::cout, ","});
}
Example 30.7 uses the function boost::irange()
. This function creates a range for integers without having to use a container or another data structure. You only pass a lower and upper bound to boost::irange()
with the upper bound being exclusive.
boost::irange()
returns a range of type boost::integer_range
. This class is derived from boost::iterator_range
. boost::iterator_range
is a template that expects an iterator type as its sole template parameter. The iterator used by boost::irange()
is tightly coupled to that function and is an implementation detail. Thus, the iterator type isn’t known and can’t be passed as a template parameter to boost::iterator_range
. However, boost::integer_range
only expects an integer type, which makes it easier to use than if you had to pass an iterator type.
Example 30.7 writes 0,1,2
to standard output.
boost::istream_range()
#include <boost/range/algorithm.hpp>
#include <boost/range/istream_range.hpp>
#include <iterator>
#include <iostream>
int main()
{
boost::iterator_range<std::istream_iterator<int>> ir =
boost::istream_range<int>(std::cin);
boost::copy(ir, std::ostream_iterator<int>{std::cout, "\n"});
}
Example 30.8 introduces the function boost::istream_range()
, which creates a range for an input stream. The function returns the range as a boost::iterator_range
. This means that an iterator type has to be passed as a template parameter.
When you start Example 30.8, type a number, and press Enter, the number is printed in the next line. If you type another number and press Enter, that number is printed. The range returned by boost::istream_range()
makes it possible for boost::copy()
to iterate over all entered numbers and write them to std::cout.
You can terminate the program any time by typing Ctrl+C.
Besides boost::iterator_range
, Boost.Range provides the class boost::sub_range
, which is derived from boost::iterator_range
. boost::sub_range
is a template like boost::iterator_range
. However, boost::sub_range
expects the type of the range as a template parameter, not an iterator type. This can simplify usage.
boost::sub_range()
#include <boost/range/algorithm.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/sub_range.hpp>
#include <array>
#include <iterator>
#include <iostream>
int main()
{
std::array<int, 6> a{{0, 1, 2, 3, 4, 5}};
boost::iterator_range<std::array<int, 6>::iterator> r1 =
boost::random_shuffle(a);
boost::sub_range<std::array<int, 6>> r2 =
boost::random_shuffle(r1);
boost::copy(r2, std::ostream_iterator<int>{std::cout, ","});
}
A few algorithms from Boost.Range return a range – for example, boost::random_shuffle()
. This algorithm directly modifies the range passed to it by reference and returns the modified range. In Example 30.9, boost::random_shuffle()
is called twice, so array a is randomly shuffled twice.
For the first return value, the example uses boost::iterator_range
; for the second return value, it uses boost::sub_range
. The usage of both classes only differs in the template parameter. Not only can boost::sub_range
be instantiated more easily, but it also provides the type definition const_iterator
.