| Home | Libraries | People | FAQ | More

#### 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;
    }