Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Method 2: provide free-standing functions and specialize metafunctions

This procedure assumes that you cannot (or do not wish to) change the types that should be made conformant to a Range concept. If this is not true, see method 1.

The primary templates in this library are implemented such that certain functions are found via argument-dependent-lookup (ADL). Below is given an overview of which free-standing functions a class must specify to be useable as a certain Range concept. Let x be a variable (const or mutable) of the class in question.

Function

Related concept

range_begin(x)

Single Pass Range

range_end(x)

Single Pass Range

range_calculate_size(x)

Optional. This can be used to specify a mechanism for constant-time computation of the size of a range. The default behaviour is to return boost::end(x) - boost::begin(x) for random access ranges, and to return x.size() for ranges with lesser traversal capability. This behaviour can be changed by implementing range_calculate_size in a manner that will be found via ADL. The ability to calculate size in O(1) is often possible even with ranges with traversal categories less than random access.

range_begin() and range_end() must be overloaded for both const and mutable reference arguments.

You must also specialize two metafunctions for your type X:

Metafunction

Related concept

boost::range_mutable_iterator

Single Pass Range

boost::range_const_iterator

Single Pass Range

A complete example is given here:

#include <boost/range.hpp>
#include <iterator>         // for std::iterator_traits, std::distance()

namespace Foo
{
    //
    // Our sample UDT. A 'Pair'
    // will work as a range when the stored
    // elements are iterators.
    //
    template< class T >
    struct Pair
    {
        T first, last;
    };

} // namespace 'Foo'

namespace boost
{
    //
    // Specialize metafunctions. We must include the range.hpp header.
    // We must open the 'boost' namespace.
    //

	template< class T >
	struct range_mutable_iterator< Foo::Pair<T> >
	{
		typedef T type;
	};

	template< class T >
	struct range_const_iterator< Foo::Pair<T> >
	{
		//
		// Remark: this is defined similar to 'range_iterator'
		//         because the 'Pair' type does not distinguish
		//         between an iterator and a const_iterator.
		//
		typedef T type;
	};

} // namespace 'boost'

namespace Foo
{
	//
	// The required functions. These should be defined in
	// the same namespace as 'Pair', in this case
	// in namespace 'Foo'.
	//

	template< class T >
	inline T range_begin( Pair<T>& x )
	{
		return x.first;
	}

	template< class T >
	inline T range_begin( const Pair<T>& x )
	{
		return x.first;
	}

	template< class T >
	inline T range_end( Pair<T>& x )
	{
		return x.last;
	}

	template< class T >
	inline T range_end( const Pair<T>& x )
	{
		return x.last;
	}

} // namespace 'Foo'

#include <vector>

int main(int argc, const char* argv[])
{
	typedef std::vector<int>::iterator  iter;
	std::vector<int>                    vec;
	Foo::Pair<iter>                     pair = { vec.begin(), vec.end() };
	const Foo::Pair<iter>&              cpair = pair;
	//
	// Notice that we call 'begin' etc with qualification.
	//
	iter i = boost::begin( pair );
	iter e = boost::end( pair );
	i      = boost::begin( cpair );
	e      = boost::end( cpair );
	boost::range_difference< Foo::Pair<iter> >::type s = boost::size( pair );
	s      = boost::size( cpair );
	boost::range_reverse_iterator< const Foo::Pair<iter> >::type
	ri     = boost::rbegin( cpair ),
	re     = boost::rend( cpair );

	return 0;
}


PrevUpHomeNext