Boost.Range |
Generic algorithms have so far been specified in terms of two or more iterators. Two iterators would together form a range of values that the algorithm could work on. This leads to a very general interface, but also to a somewhat clumsy use of the algorithms with redundant specification of container names. Therefore we would like to raise the abstraction level for algorithms so they specify their interface in terms of Ranges as much as possible.
The most common form of ranges we are used to work with is standard library containers. However, one often finds it desirable to extend that code to work with other types that offer enough functionality to satisfy the needs of the generic code if a suitable layer of indirection is applied . For example, raw arrays are often suitable for use with generic code that works with containers, provided a suitable adapter is used. Likewise, null terminated strings can be treated as containers of characters, if suitably adapted.
This library therefore provides the means to adapt standard-like
containers,
null terminated strings, std::pairs
of iterators, and raw
arrays (and more), such that the same generic code can work with them all.
The basic idea is to add another layer of indirection using metafunctions and
free-standing functions so syntactic and/or semantic differences can be removed.
The main advantages are
Warning: support for null-terminated strings is deprecated and will disappear in the next Boost release (1.34).
Below are given a small example (the complete example can be found here ):
By using the free-standing functions and metafunctions, the code automatically works for all the types supported by this library; now and in the future. Notice that we have to provide two version of// // example: extracting bounds in a generic algorithm // template< class ForwardReadableRange, class T > inline typename boost::range_iterator< ForwardReadableRange >::type find( ForwardReadableRange& c, const T& value ) { return std::find( boost::begin( c ), boost::end( c ), value ); } template< class ForwardReadableRange, class T > inline typename boost::range_const_iterator< ForwardReadableRange >::type find( const ForwardReadableRange& c, const T& value ) { return std::find( boost::begin( c ), boost::end( c ), value ); } // // replace first value and return its index // template< class ForwardReadableWriteableRange, class T > inline typename boost::range_size< ForwardReadableWriteableRange >::type my_generic_replace( ForwardReadableWriteableRange& c, const T& value, const T& replacement ) { typename boost::range_iterator< ForwardReadableWriteableRange >::type found = find( c, value ); if( found != boost::end( c ) ) *found = replacement; return std::distance( boost::begin( c ), found ); } // // usage // const int N = 5; std::vector<int> my_vector; int values[] = { 1,2,3,4,5,6,7,8,9 }; my_vector.assign( values, boost::end( values ) ); typedef std::vector<int>::iterator iterator; std::pair<iterator,iterator> my_view( boost::begin( my_vector ), boost::begin( my_vector ) + N ); char str_val[] = "a string"; char* str = str_val; std::cout << my_generic_replace( my_vector, 4, 2 ); std::cout << my_generic_replace( my_view, 4, 2 ); std::cout << my_generic_replace( str, 'a', 'b' ); // prints '3', '5' and '0'
find()
since we cannot forward a non-const
rvalue with reference arguments (see this article about The
Forwarding Problem ).
(C) Copyright Thorsten Ottosen 2003-2004