![]() |
|
This library makes it possible to treat different types as if they have
implemented a subset of the container requirements
(see §23.1of the C++ standard). Formally, that subset is defined by
the CollectionConcept.
The subset deals mostly with
iterator returning functions and nested typedef
s.
The main goal is to treat built-in arrays, standard containers,
pairs of iterators and some iterators uniformly. Formally, this library is an implementation
of the ExternalCollectionConcept (see also this explanation of External Concepts ).
The main advantages are
Below are given a small example (the complete example can be found here ):
// // Example: extracting bounds in generic algorithms // template< typename ExternalCollection, typename T > inline typename boost::iterator_of<ExternalCollection>::type find( ExternalCollection& c, const T& value ) { return std::find( boost::begin( c ), boost::end( c ), value ); } template< typename ExternalCollection, typename T > inline typename boost::const_iterator_of<ExternalCollection>::type find( const ExternalCollection& c, const T& value ) { return std::find( boost::begin( c ), boost::end( c ), value ); } // // replace first value and return its index // template< typename EC, typename T > inline typename boost::size_type_of< EC >::type my_generic_replace( EC& c, const T& value, const T& replacement ) { typename boost::const_iterator_of<EC>::type found = find( c, value ); *found = replacement; return std::distance( boost::begin( c ), found ); } // // usage // std::vector<int> my_vector; typedef vector<int>::iterator iterator; std::pair<iterator,iterator> my_view( my_vector.begin(), my_vector.begin() + N ); char str[] = "a string"; // ... std::cout << my_generic_replace( my_vector, 4, 2 ) << my_generic_replace( my_view, 4, 2 ) << my_generic_replace( str, 'a', 'b' );By using the free-standing functions and type-generators, the code automatically works for all the types supported by this library. Notice that we have to provide two version of
find()
since we cannot
forward a non-const rvalue with reference arguments (see this article about The Forwarding Problem ).#include <boost/collection_traits.hpp>
Five types of objects are currently supported by the library:
char[]
,wchar_t[]
,char*
, and wchar_t*
)std::pair<iterator,iterator>
boost::array<>
anyway). Also note that arrays and pointers of char
or whar_t
are treated special because of their use in string algorithms.The concept is defined by the type-generators and the
functions below. Even though these functions are defined in
namespace boost
, there is no such general requirement, that is,
if one wants to extend the list of supported types, it can be done in any
namespace.
namespace boost { // // type generators // template< typename EC > struct value_type_of { typedef ... type; // type of stored objects }; template< typename EC > struct iterator_of { typedef ... type; // iterator over stored objects }; template< typename EC > struct const_iterator_of { typedef ... type; // iterator over immutable stored objects }; template< typename EC > struct difference_type_of { typedef ... type; BOOST_STATIC_ASSERT( boost::is_signed< type >::value ); // // remark: if std::iterator_traits<> works for the type, this assertion must hold // BOOST_STATIC_ASSERT( boost::is_same< type, std::iterator_traits< typename iterator_of< EC >::type >::difference_type>::value ); }; template< typename EC > struct size_type_of { typedef ... type; BOOST_STATIC_ASSERT( boost::is_unsigned< type >::value ); BOOST_STATIC_ASSERT( sizeof( type ) >= sizeof( difference_type_of< EC >::type ) ); }; template< typename EC > struct result_iterator_of { typedef ... type; // iterator_of< EC >::type if EC is non-const, const_iterator_of< EC >::type otherwise }; // // funtions // template< typename EC > inline typename iterator_of::type begin( EC& c ); template< typename EC > inline typename const_iterator_of< EC >::type begin( const EC& c ); template< typename EC > inline typename iterator_of< EC >::type end( EC& c ); template< typename EC > inline typename const_iterator_of< EC >::type end( const EC& c ); template< typename EC > inline bool empty( const EC& c ); template< typename EC > inline typename size_type_of< EC >::type size( const EC& c ); } // namespace 'boost'
Header | Includes |
---|---|
<boost/collection_traits.hpp> | everything |
<boost/collection_traits/types.hpp> | every type-generator |
<boost/collection_traits/functions.hpp> | every function |
<boost/collection_traits/value_type.hpp> | value_type_of |
<boost/collection_traits/iterator.hpp> | iterator_of |
<boost/collection_traits/const_iterator.hpp> | const_iterator_of |
<boost/collection_traits/difference_type.hpp> | difference_type_of |
<boost/collection_traits/size_type.hpp> | size_type_of |
<boost/collection_traits/result_iterator.hpp> | result_iterator_of |
<boost/collection_traits/begin.hpp> | begin |
<boost/collection_traits/end.hpp> | end |
<boost/collection_traits/empty.hpp> | empty |
<boost/collection_traits/size.hpp> | size |
In the table C
is a type that conforms to the ExternalCollectionConcept and c
is an object of that type. SC
will denote a standard
container, T[sz]
will denote an array of type T
of size sz
, P
will denote std::pair<>
, I
means an iterator which default construction
denotes the end of the range and sc,t,p,i
are objects of these types,
respectively. Special cases for char*
and wchar_t*
are described explicitly.
Please note that char*
,whar_t*
,char[]
, and wchar_t[]
behaves differently from
normal arrays only for size()
and end()
.
Note that the null pointer is allowed as an argument in these cases.
Some examples are given in the accompanying test files:
iterator.cpp
std::copy()
that works with std::ifstream_iterator<>.
string.cpp
std::find()
that works with char[],wchar_t[],char*,wchar_t*.
algorithm_example.cpp
Full support for built-in arrays require that the compiler supports class template partial specialization.
Notice that some compilers cannot do function template ordering
properly. In that case one cannot rely of result_iterator_of<>
and a single function definition; instead one needs to supply
a function overloaded for const and non-const arguments if it is required.
Full support for iterators like std::istream_iterator<>
depends very
much on a conforming standard library.
Most of the tests have been run successfully on these compilers
iterator_of<C>::type
and const_iterator_of<C>::type
for std::pair<iterator,iterator>
or iterators which default construction denotes the end of the range?In general it is not possible nor desirable to find a corresponding const_iterator
. When it is possible to come up with
one, the client might choose to
construct a std::pair<const_iterator,const_iterator>
object.
The traits class have been kept small because its current interface will serve most purposes. If and when a genuine need arises for more functionality, it can be implemented.
One should always start with a generic algorithm that takes two iterators as input. Then use the collection traits to build handier versions on top of the base algorithm.
The library have been under way for a long time. Dietmar Kühl originally
intended to submit an array_traits<>
class template which had most
of the functionality present now, but only for arrays and standard containers.
Meanwhile work on container algorithms
in various context showed the need for handling pairs of iterators, and
string libraries needed special treatment of character arrays.
Thorsten Ottosen wrote everything from the ground up including the first
work-around for missing partial template specialization. Pavol Droba helped to
improve the work-around for handicapped compilers and the special character support.
The naming scheme of type-generators was suggested by Peter Dimov.
© Thorsten Ottosen 2003-2004 (nesotto_AT_cs.auc.dk). Permission to copy, use, modify, sell and distribute this software is granted provided this copyright notice appears in all copies. This software is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.