forked from boostorg/utility
This commit was manufactured by cvs2svn to create branch
'unlabeled-1.8.2'. [SVN r9368]
This commit is contained in:
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
* text=auto !eol svneol=native#text/plain
|
||||||
|
*.gitattributes text svneol=native#text/plain
|
||||||
|
|
||||||
|
# Scriptish formats
|
||||||
|
*.bat text svneol=native#text/plain
|
||||||
|
*.bsh text svneol=native#text/x-beanshell
|
||||||
|
*.cgi text svneol=native#text/plain
|
||||||
|
*.cmd text svneol=native#text/plain
|
||||||
|
*.js text svneol=native#text/javascript
|
||||||
|
*.php text svneol=native#text/x-php
|
||||||
|
*.pl text svneol=native#text/x-perl
|
||||||
|
*.pm text svneol=native#text/x-perl
|
||||||
|
*.py text svneol=native#text/x-python
|
||||||
|
*.sh eol=lf svneol=LF#text/x-sh
|
||||||
|
configure eol=lf svneol=LF#text/x-sh
|
||||||
|
|
||||||
|
# Image formats
|
||||||
|
*.bmp binary svneol=unset#image/bmp
|
||||||
|
*.gif binary svneol=unset#image/gif
|
||||||
|
*.ico binary svneol=unset#image/ico
|
||||||
|
*.jpeg binary svneol=unset#image/jpeg
|
||||||
|
*.jpg binary svneol=unset#image/jpeg
|
||||||
|
*.png binary svneol=unset#image/png
|
||||||
|
*.tif binary svneol=unset#image/tiff
|
||||||
|
*.tiff binary svneol=unset#image/tiff
|
||||||
|
*.svg text svneol=native#image/svg%2Bxml
|
||||||
|
|
||||||
|
# Data formats
|
||||||
|
*.pdf binary svneol=unset#application/pdf
|
||||||
|
*.avi binary svneol=unset#video/avi
|
||||||
|
*.doc binary svneol=unset#application/msword
|
||||||
|
*.dsp text svneol=crlf#text/plain
|
||||||
|
*.dsw text svneol=crlf#text/plain
|
||||||
|
*.eps binary svneol=unset#application/postscript
|
||||||
|
*.gz binary svneol=unset#application/gzip
|
||||||
|
*.mov binary svneol=unset#video/quicktime
|
||||||
|
*.mp3 binary svneol=unset#audio/mpeg
|
||||||
|
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||||
|
*.ps binary svneol=unset#application/postscript
|
||||||
|
*.psd binary svneol=unset#application/photoshop
|
||||||
|
*.rdf binary svneol=unset#text/rdf
|
||||||
|
*.rss text svneol=unset#text/xml
|
||||||
|
*.rtf binary svneol=unset#text/rtf
|
||||||
|
*.sln text svneol=native#text/plain
|
||||||
|
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||||
|
*.tgz binary svneol=unset#application/gzip
|
||||||
|
*.vcproj text svneol=native#text/xml
|
||||||
|
*.vcxproj text svneol=native#text/xml
|
||||||
|
*.vsprops text svneol=native#text/xml
|
||||||
|
*.wav binary svneol=unset#audio/wav
|
||||||
|
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||||
|
*.zip binary svneol=unset#application/zip
|
||||||
|
|
||||||
|
# Text formats
|
||||||
|
.htaccess text svneol=native#text/plain
|
||||||
|
*.bbk text svneol=native#text/xml
|
||||||
|
*.cmake text svneol=native#text/plain
|
||||||
|
*.css text svneol=native#text/css
|
||||||
|
*.dtd text svneol=native#text/xml
|
||||||
|
*.htm text svneol=native#text/html
|
||||||
|
*.html text svneol=native#text/html
|
||||||
|
*.ini text svneol=native#text/plain
|
||||||
|
*.log text svneol=native#text/plain
|
||||||
|
*.mak text svneol=native#text/plain
|
||||||
|
*.qbk text svneol=native#text/plain
|
||||||
|
*.rst text svneol=native#text/plain
|
||||||
|
*.sql text svneol=native#text/x-sql
|
||||||
|
*.txt text svneol=native#text/plain
|
||||||
|
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||||
|
*.xml text svneol=native#text/xml
|
||||||
|
*.xsd text svneol=native#text/xml
|
||||||
|
*.xsl text svneol=native#text/xml
|
||||||
|
*.xslt text svneol=native#text/xml
|
||||||
|
*.xul text svneol=native#text/xul
|
||||||
|
*.yml text svneol=native#text/plain
|
||||||
|
boost-no-inspect text svneol=native#text/plain
|
||||||
|
CHANGES text svneol=native#text/plain
|
||||||
|
COPYING text svneol=native#text/plain
|
||||||
|
INSTALL text svneol=native#text/plain
|
||||||
|
Jamfile text svneol=native#text/plain
|
||||||
|
Jamroot text svneol=native#text/plain
|
||||||
|
Jamfile.v2 text svneol=native#text/plain
|
||||||
|
Jamrules text svneol=native#text/plain
|
||||||
|
Makefile* text svneol=native#text/plain
|
||||||
|
README text svneol=native#text/plain
|
||||||
|
TODO text svneol=native#text/plain
|
||||||
|
|
||||||
|
# Code formats
|
||||||
|
*.c text svneol=native#text/plain
|
||||||
|
*.cpp text svneol=native#text/plain
|
||||||
|
*.h text svneol=native#text/plain
|
||||||
|
*.hpp text svneol=native#text/plain
|
||||||
|
*.ipp text svneol=native#text/plain
|
||||||
|
*.tpp text svneol=native#text/plain
|
||||||
|
*.jam text svneol=native#text/plain
|
||||||
|
*.java text svneol=native#text/plain
|
366
call_traits_test.cpp
Normal file
366
call_traits_test.cpp
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
// boost::compressed_pair test program
|
||||||
|
|
||||||
|
// (C) Copyright John Maddock 2000. 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.
|
||||||
|
|
||||||
|
// standalone test program for <boost/call_traits.hpp>
|
||||||
|
// 03 Oct 2000:
|
||||||
|
// Enabled extra tests for VC6.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <boost/call_traits.hpp>
|
||||||
|
|
||||||
|
#include "type_traits_test.hpp"
|
||||||
|
//
|
||||||
|
// struct contained models a type that contains a type (for example std::pair)
|
||||||
|
// arrays are contained by value, and have to be treated as a special case:
|
||||||
|
//
|
||||||
|
template <class T>
|
||||||
|
struct contained
|
||||||
|
{
|
||||||
|
// define our typedefs first, arrays are stored by value
|
||||||
|
// so value_type is not the same as result_type:
|
||||||
|
typedef typename boost::call_traits<T>::param_type param_type;
|
||||||
|
typedef typename boost::call_traits<T>::reference reference;
|
||||||
|
typedef typename boost::call_traits<T>::const_reference const_reference;
|
||||||
|
typedef T value_type;
|
||||||
|
typedef typename boost::call_traits<T>::value_type result_type;
|
||||||
|
|
||||||
|
// stored value:
|
||||||
|
value_type v_;
|
||||||
|
|
||||||
|
// constructors:
|
||||||
|
contained() {}
|
||||||
|
contained(param_type p) : v_(p){}
|
||||||
|
// return byval:
|
||||||
|
result_type value()const { return v_; }
|
||||||
|
// return by_ref:
|
||||||
|
reference get() { return v_; }
|
||||||
|
const_reference const_get()const { return v_; }
|
||||||
|
// pass value:
|
||||||
|
void call(param_type p){}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
struct contained<T[N]>
|
||||||
|
{
|
||||||
|
typedef typename boost::call_traits<T[N]>::param_type param_type;
|
||||||
|
typedef typename boost::call_traits<T[N]>::reference reference;
|
||||||
|
typedef typename boost::call_traits<T[N]>::const_reference const_reference;
|
||||||
|
typedef T value_type[N];
|
||||||
|
typedef typename boost::call_traits<T[N]>::value_type result_type;
|
||||||
|
|
||||||
|
value_type v_;
|
||||||
|
|
||||||
|
contained(param_type p)
|
||||||
|
{
|
||||||
|
std::copy(p, p+N, v_);
|
||||||
|
}
|
||||||
|
// return byval:
|
||||||
|
result_type value()const { return v_; }
|
||||||
|
// return by_ref:
|
||||||
|
reference get() { return v_; }
|
||||||
|
const_reference const_get()const { return v_; }
|
||||||
|
void call(param_type p){}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
contained<typename boost::call_traits<T>::value_type> wrap(const T& t)
|
||||||
|
{
|
||||||
|
typedef typename boost::call_traits<T>::value_type ct;
|
||||||
|
return contained<ct>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace test{
|
||||||
|
|
||||||
|
template <class T1, class T2>
|
||||||
|
std::pair<
|
||||||
|
typename boost::call_traits<T1>::value_type,
|
||||||
|
typename boost::call_traits<T2>::value_type>
|
||||||
|
make_pair(const T1& t1, const T2& t2)
|
||||||
|
{
|
||||||
|
return std::pair<
|
||||||
|
typename boost::call_traits<T1>::value_type,
|
||||||
|
typename boost::call_traits<T2>::value_type>(t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct checker:
|
||||||
|
// verifies behaviour of contained example:
|
||||||
|
//
|
||||||
|
template <class T>
|
||||||
|
struct checker
|
||||||
|
{
|
||||||
|
typedef typename boost::call_traits<T>::param_type param_type;
|
||||||
|
void operator()(param_type);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void checker<T>::operator()(param_type p)
|
||||||
|
{
|
||||||
|
T t(p);
|
||||||
|
contained<T> c(t);
|
||||||
|
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
|
||||||
|
assert(t == c.value());
|
||||||
|
assert(t == c.get());
|
||||||
|
assert(t == c.const_get());
|
||||||
|
|
||||||
|
//cout << "typeof contained<" << typeid(T).name() << ">::v_ is: " << typeid(&contained<T>::v_).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T).name() << ">::value() is: " << typeid(&contained<T>::value).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T).name() << ">::get() is: " << typeid(&contained<T>::get).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T).name() << ">::const_get() is: " << typeid(&contained<T>::const_get).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T).name() << ">::call() is: " << typeid(&contained<T>::call).name() << endl;
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
struct checker<T[N]>
|
||||||
|
{
|
||||||
|
typedef typename boost::call_traits<T[N]>::param_type param_type;
|
||||||
|
void operator()(param_type t)
|
||||||
|
{
|
||||||
|
contained<T[N]> c(t);
|
||||||
|
cout << "checking contained<" << typeid(T[N]).name() << ">..." << endl;
|
||||||
|
unsigned int i = 0;
|
||||||
|
for(i = 0; i < N; ++i)
|
||||||
|
assert(t[i] == c.value()[i]);
|
||||||
|
for(i = 0; i < N; ++i)
|
||||||
|
assert(t[i] == c.get()[i]);
|
||||||
|
for(i = 0; i < N; ++i)
|
||||||
|
assert(t[i] == c.const_get()[i]);
|
||||||
|
|
||||||
|
cout << "typeof contained<" << typeid(T[N]).name() << ">::v_ is: " << typeid(&contained<T[N]>::v_).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T[N]).name() << ">::value is: " << typeid(&contained<T[N]>::value).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T[N]).name() << ">::get is: " << typeid(&contained<T[N]>::get).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T[N]).name() << ">::const_get is: " << typeid(&contained<T[N]>::const_get).name() << endl;
|
||||||
|
cout << "typeof contained<" << typeid(T[N]).name() << ">::call is: " << typeid(&contained<T[N]>::call).name() << endl;
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// check_wrap:
|
||||||
|
template <class T, class U>
|
||||||
|
void check_wrap(const contained<T>& w, const U& u)
|
||||||
|
{
|
||||||
|
cout << "checking contained<" << typeid(T).name() << ">..." << endl;
|
||||||
|
assert(w.value() == u);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check_make_pair:
|
||||||
|
// verifies behaviour of "make_pair":
|
||||||
|
//
|
||||||
|
template <class T, class U, class V>
|
||||||
|
void check_make_pair(T c, U u, V v)
|
||||||
|
{
|
||||||
|
cout << "checking std::pair<" << typeid(c.first).name() << ", " << typeid(c.second).name() << ">..." << endl;
|
||||||
|
assert(c.first == u);
|
||||||
|
assert(c.second == v);
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct UDT
|
||||||
|
{
|
||||||
|
int i_;
|
||||||
|
UDT() : i_(2){}
|
||||||
|
bool operator == (const UDT& v){ return v.i_ == i_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
checker<UDT> c1;
|
||||||
|
UDT u;
|
||||||
|
c1(u);
|
||||||
|
checker<int> c2;
|
||||||
|
int i = 2;
|
||||||
|
c2(i);
|
||||||
|
int* pi = &i;
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
|
checker<int*> c3;
|
||||||
|
c3(pi);
|
||||||
|
checker<int&> c4;
|
||||||
|
c4(i);
|
||||||
|
checker<const int&> c5;
|
||||||
|
c5(i);
|
||||||
|
#if !defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||||
|
int a[2] = {1,2};
|
||||||
|
checker<int[2]> c6;
|
||||||
|
c6(a);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
check_wrap(wrap(2), 2);
|
||||||
|
const char ca[4] = "abc";
|
||||||
|
// compiler can't deduce this for some reason:
|
||||||
|
//check_wrap(wrap(ca), ca);
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
check_wrap(wrap(a), a);
|
||||||
|
check_make_pair(test::make_pair(a, a), a, a);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// cv-qualifiers applied to reference types should have no effect
|
||||||
|
// declare these here for later use with is_reference and remove_reference:
|
||||||
|
typedef int& r_type;
|
||||||
|
typedef const r_type cr_type;
|
||||||
|
|
||||||
|
type_test(UDT, boost::call_traits<UDT>::value_type)
|
||||||
|
type_test(UDT&, boost::call_traits<UDT>::reference)
|
||||||
|
type_test(const UDT&, boost::call_traits<UDT>::const_reference)
|
||||||
|
type_test(const UDT&, boost::call_traits<UDT>::param_type)
|
||||||
|
type_test(int, boost::call_traits<int>::value_type)
|
||||||
|
type_test(int&, boost::call_traits<int>::reference)
|
||||||
|
type_test(const int&, boost::call_traits<int>::const_reference)
|
||||||
|
type_test(const int, boost::call_traits<int>::param_type)
|
||||||
|
type_test(int*, boost::call_traits<int*>::value_type)
|
||||||
|
type_test(int*&, boost::call_traits<int*>::reference)
|
||||||
|
type_test(int*const&, boost::call_traits<int*>::const_reference)
|
||||||
|
type_test(int*const, boost::call_traits<int*>::param_type)
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
|
type_test(int&, boost::call_traits<int&>::value_type)
|
||||||
|
type_test(int&, boost::call_traits<int&>::reference)
|
||||||
|
type_test(const int&, boost::call_traits<int&>::const_reference)
|
||||||
|
type_test(int&, boost::call_traits<int&>::param_type)
|
||||||
|
#if !(defined(__GNUC__) && (__GNUC__ < 3))
|
||||||
|
type_test(int&, boost::call_traits<cr_type>::value_type)
|
||||||
|
type_test(int&, boost::call_traits<cr_type>::reference)
|
||||||
|
type_test(const int&, boost::call_traits<cr_type>::const_reference)
|
||||||
|
type_test(int&, boost::call_traits<cr_type>::param_type)
|
||||||
|
#else
|
||||||
|
std::cout << "Your compiler cannot instantiate call_traits<int&const>, skipping four tests (4 errors)" << std::endl;
|
||||||
|
failures += 4;
|
||||||
|
test_count += 4;
|
||||||
|
#endif
|
||||||
|
type_test(const int&, boost::call_traits<const int&>::value_type)
|
||||||
|
type_test(const int&, boost::call_traits<const int&>::reference)
|
||||||
|
type_test(const int&, boost::call_traits<const int&>::const_reference)
|
||||||
|
type_test(const int&, boost::call_traits<const int&>::param_type)
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
type_test(const int*, boost::call_traits<int[3]>::value_type)
|
||||||
|
type_test(int(&)[3], boost::call_traits<int[3]>::reference)
|
||||||
|
type_test(const int(&)[3], boost::call_traits<int[3]>::const_reference)
|
||||||
|
type_test(const int*const, boost::call_traits<int[3]>::param_type)
|
||||||
|
type_test(const int*, boost::call_traits<const int[3]>::value_type)
|
||||||
|
type_test(const int(&)[3], boost::call_traits<const int[3]>::reference)
|
||||||
|
type_test(const int(&)[3], boost::call_traits<const int[3]>::const_reference)
|
||||||
|
type_test(const int*const, boost::call_traits<const int[3]>::param_type)
|
||||||
|
#else
|
||||||
|
std::cout << "You're compiler does not support partial template instantiation, skipping 8 tests (8 errors)" << std::endl;
|
||||||
|
failures += 8;
|
||||||
|
test_count += 8;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
std::cout << "You're compiler does not support partial template instantiation, skipping 20 tests (20 errors)" << std::endl;
|
||||||
|
failures += 20;
|
||||||
|
test_count += 20;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::cout << std::endl << test_count << " tests completed (" << failures << " failures)... press any key to exit";
|
||||||
|
std::cin.get();
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// define call_traits tests to check that the assertions in the docs do actually work
|
||||||
|
// this is an instantiate only set of tests:
|
||||||
|
//
|
||||||
|
template <typename T, bool isarray = false>
|
||||||
|
struct call_traits_test
|
||||||
|
{
|
||||||
|
typedef ::boost::call_traits<T> ct;
|
||||||
|
typedef typename ct::param_type param_type;
|
||||||
|
typedef typename ct::reference reference;
|
||||||
|
typedef typename ct::const_reference const_reference;
|
||||||
|
typedef typename ct::value_type value_type;
|
||||||
|
static void assert_construct(param_type val);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, bool isarray>
|
||||||
|
void call_traits_test<T, isarray>::assert_construct(typename call_traits_test<T, isarray>::param_type val)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// this is to check that the call_traits assertions are valid:
|
||||||
|
T t(val);
|
||||||
|
value_type v(t);
|
||||||
|
reference r(t);
|
||||||
|
const_reference cr(t);
|
||||||
|
param_type p(t);
|
||||||
|
value_type v2(v);
|
||||||
|
value_type v3(r);
|
||||||
|
value_type v4(p);
|
||||||
|
reference r2(v);
|
||||||
|
reference r3(r);
|
||||||
|
const_reference cr2(v);
|
||||||
|
const_reference cr3(r);
|
||||||
|
const_reference cr4(cr);
|
||||||
|
const_reference cr5(p);
|
||||||
|
param_type p2(v);
|
||||||
|
param_type p3(r);
|
||||||
|
param_type p4(p);
|
||||||
|
}
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
template <typename T>
|
||||||
|
struct call_traits_test<T, true>
|
||||||
|
{
|
||||||
|
typedef ::boost::call_traits<T> ct;
|
||||||
|
typedef typename ct::param_type param_type;
|
||||||
|
typedef typename ct::reference reference;
|
||||||
|
typedef typename ct::const_reference const_reference;
|
||||||
|
typedef typename ct::value_type value_type;
|
||||||
|
static void assert_construct(param_type val);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void call_traits_test<T, true>::assert_construct(typename boost::call_traits<T>::param_type val)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// this is to check that the call_traits assertions are valid:
|
||||||
|
T t;
|
||||||
|
value_type v(t);
|
||||||
|
value_type v5(val);
|
||||||
|
reference r = t;
|
||||||
|
const_reference cr = t;
|
||||||
|
reference r2 = r;
|
||||||
|
#ifndef __BORLANDC__
|
||||||
|
// C++ Builder buglet:
|
||||||
|
const_reference cr2 = r;
|
||||||
|
#endif
|
||||||
|
param_type p(t);
|
||||||
|
value_type v2(v);
|
||||||
|
const_reference cr3 = cr;
|
||||||
|
value_type v3(r);
|
||||||
|
value_type v4(p);
|
||||||
|
param_type p2(v);
|
||||||
|
param_type p3(r);
|
||||||
|
param_type p4(p);
|
||||||
|
}
|
||||||
|
#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
//
|
||||||
|
// now check call_traits assertions by instantiating call_traits_test:
|
||||||
|
template struct call_traits_test<int>;
|
||||||
|
template struct call_traits_test<const int>;
|
||||||
|
template struct call_traits_test<int*>;
|
||||||
|
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||||
|
template struct call_traits_test<int&>;
|
||||||
|
template struct call_traits_test<const int&>;
|
||||||
|
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||||
|
template struct call_traits_test<int[2], true>;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
325
counting_iterator.htm
Normal file
325
counting_iterator.htm
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||||
|
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||||
|
<title>Counting Iterator Adaptor Documentation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body bgcolor="#FFFFFF" text="#000000">
|
||||||
|
|
||||||
|
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||||
|
align="center" width="277" height="86">
|
||||||
|
|
||||||
|
<h1>Counting Iterator Adaptor</h1>
|
||||||
|
|
||||||
|
Defined in header
|
||||||
|
<a href="../../boost/counting_iterator.hpp">boost/counting_iterator.hpp</a>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
How would you fill up a vector with the numbers zero
|
||||||
|
through one hundred using <a
|
||||||
|
href="http://www.sgi.com/tech/stl/copy.html"><tt>std::copy()</tt></a>? The
|
||||||
|
only iterator operation missing from builtin integer types is an
|
||||||
|
<tt>operator*()</tt> that returns the current
|
||||||
|
value of the integer. The counting iterator adaptor adds this crucial piece of
|
||||||
|
functionality to whatever type it wraps. One can use the
|
||||||
|
counting iterator adaptor not only with integer types, but with any
|
||||||
|
type that is <tt>Incrementable</tt> (see type requirements <a href="#requirements">below</a>). The
|
||||||
|
following <b>pseudo-code</b> shows the general idea of how the
|
||||||
|
counting iterator is implemented.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// inside a hypothetical counting_iterator class...
|
||||||
|
typedef Incrementable value_type;
|
||||||
|
value_type counting_iterator::operator*() const {
|
||||||
|
return this->base; // no dereference!
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
All of the other operators of the counting iterator behave in the same
|
||||||
|
fashion as the <tt>Incrementable</tt> base type.
|
||||||
|
|
||||||
|
<h2>Synopsis</h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
namespace boost {
|
||||||
|
template <class Incrementable>
|
||||||
|
struct <a href="#counting_iterator_traits">counting_iterator_traits</a>;
|
||||||
|
|
||||||
|
template <class Incrementable>
|
||||||
|
struct <a href="#counting_iterator_generator">counting_iterator_generator</a>;
|
||||||
|
|
||||||
|
template <class Incrementable>
|
||||||
|
typename counting_iterator_generator<Incrementable>::type
|
||||||
|
<a href="#make_counting_iterator">make_counting_iterator</a>(Incrementable x);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><a name="counting_iterator_generator">The Counting Iterator Type
|
||||||
|
Generator</a></h2>
|
||||||
|
|
||||||
|
The class template <tt>counting_iterator_generator<Incrementable></tt> is a <a href="../../more/generic_programming.html#type_generator">type generator</a> for counting iterators.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
template <class Incrementable>
|
||||||
|
class counting_iterator_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef <a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...> type;
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h3>Example</h3>
|
||||||
|
|
||||||
|
In this example we use the counting iterator generator to create a
|
||||||
|
counting iterator, and count from zero to four.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/counting_iterator.hpp>
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
// Example of using counting_iterator_generator
|
||||||
|
std::cout << "counting from 0 to 4:" << std::endl;
|
||||||
|
boost::counting_iterator_generator<int>::type first(0), last(4);
|
||||||
|
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// to be continued...
|
||||||
|
</pre>
|
||||||
|
The output from this part is:
|
||||||
|
<pre>
|
||||||
|
counting from 0 to 4:
|
||||||
|
0 1 2 3
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h3>Template Parameters</h3>
|
||||||
|
|
||||||
|
<Table border>
|
||||||
|
<TR>
|
||||||
|
<TH>Parameter</TH><TH>Description</TH>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
<TR>
|
||||||
|
<TD><tt>Incrementable</tt></TD>
|
||||||
|
<TD>The type being wrapped by the adaptor.</TD>
|
||||||
|
</TR>
|
||||||
|
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<h3>Model of</h3>
|
||||||
|
|
||||||
|
If the <tt>Incrementable</tt> type has all of the functionality of a
|
||||||
|
<a href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||||
|
Access Iterator</a> except the <tt>operator*()</tt>, then the counting
|
||||||
|
iterator will be a model of <a
|
||||||
|
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||||
|
Access Iterator</a>. If the <tt>Incrementable</tt> type has less
|
||||||
|
functionality, then the counting iterator will have correspondingly
|
||||||
|
less functionality.
|
||||||
|
|
||||||
|
<h3><a name="requirements">Type Requirements</a></h3>
|
||||||
|
|
||||||
|
The <tt>Incrementable</tt> type must be <a
|
||||||
|
href="http://www.sgi.com/tech/stl/DefaultConstructible.html">Default
|
||||||
|
Constructible</a>, <a href="./CopyConstructible.html">Copy
|
||||||
|
Constructible</a>, and <a href="./Assignable.html">Assignable</a>.
|
||||||
|
Also, the <tt>Incrementable</tt> type must provide access to an
|
||||||
|
associated <tt>difference_type</tt> and <tt>iterator_category</tt>
|
||||||
|
through the <a
|
||||||
|
href="#counting_iterator_traits"><tt>counting_iterator_traits</tt></a>
|
||||||
|
class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Furthermore, if you wish to create a counting iterator that is a <a
|
||||||
|
href="http://www.sgi.com/tech/stl/ForwardIterator.html"> Forward
|
||||||
|
Iterator</a>, then the following expressions must be valid:
|
||||||
|
<pre>
|
||||||
|
Incrementable i, j;
|
||||||
|
++i // pre-increment
|
||||||
|
i == j // operator equal
|
||||||
|
</pre>
|
||||||
|
If you wish to create a counting iterator that is a <a
|
||||||
|
href="http://www.sgi.com/tech/stl/BidirectionalIterator.html">
|
||||||
|
Bidirectional Iterator</a>, then pre-decrement is also required:
|
||||||
|
<pre>
|
||||||
|
--i
|
||||||
|
</pre>
|
||||||
|
If you wish to create a counting iterator that is a <a
|
||||||
|
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html"> Random
|
||||||
|
Access Iterator</a>, then these additional expressions are also required:
|
||||||
|
<pre>
|
||||||
|
<a href="#counting_iterator_traits">counting_iterator_traits</a><Incrementable>::difference_type n;
|
||||||
|
i += n
|
||||||
|
n = i - j
|
||||||
|
i < j
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Members</h3>
|
||||||
|
|
||||||
|
The counting iterator type implements the member functions and
|
||||||
|
operators required of the <a
|
||||||
|
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||||
|
Access Iterator</a> concept. In addition it has the following
|
||||||
|
constructor:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
counting_iterator_generator::type(const Incrementable& i)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<hr>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="make_counting_iterator">The Counting Iterator Object Generator</a></h2>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
template <class Incrementable>
|
||||||
|
typename counting_iterator_generator<Incrementable>::type
|
||||||
|
make_counting_iterator(Incrementable base);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
An <a href="../../more/generic_programming.html#object_generator">object
|
||||||
|
generator</a> function that provides a convenient way to create counting
|
||||||
|
iterators.<p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Example</h3>
|
||||||
|
|
||||||
|
In this example we count from negative five to positive five, this
|
||||||
|
time using the <tt>make_counting_iterator()</tt> function to save some
|
||||||
|
typing.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// continuing from previous example...
|
||||||
|
|
||||||
|
std::cout << "counting from -5 to 4:" << std::endl;
|
||||||
|
std::copy(boost::make_counting_iterator(-5),
|
||||||
|
boost::make_counting_iterator(5),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// to be continued...
|
||||||
|
</pre>
|
||||||
|
The output from this part is:
|
||||||
|
<pre>
|
||||||
|
counting from -5 to 4:
|
||||||
|
-5 -4 -3 -2 -1 0 1 2 3 4
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
In the next example we create an array of numbers, and then create a
|
||||||
|
second array of pointers, where each pointer is the address of a
|
||||||
|
number in the first array. The counting iterator makes it easy to do
|
||||||
|
this since dereferencing a counting iterator that is wrapping an
|
||||||
|
iterator over the array of numbers just returns a pointer to the
|
||||||
|
current location in the array. We then use the <a
|
||||||
|
href="./indirect_iterator.htm">indirect iterator adaptor</a> to print
|
||||||
|
out the number in the array by accessing the numbers through the array
|
||||||
|
of pointers.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// continuing from previous example...
|
||||||
|
|
||||||
|
const int N = 7;
|
||||||
|
std::vector<int> numbers;
|
||||||
|
// Fill "numbers" array with [0,N)
|
||||||
|
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
|
||||||
|
std::back_inserter(numbers));
|
||||||
|
|
||||||
|
std::vector<std::vector<int>::iterator> pointers;
|
||||||
|
|
||||||
|
// Use counting iterator to fill in the array of pointers.
|
||||||
|
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||||
|
boost::make_counting_iterator(numbers.end()),
|
||||||
|
std::back_inserter(pointers));
|
||||||
|
|
||||||
|
// Use indirect iterator to print out numbers by accessing
|
||||||
|
// them through the array of pointers.
|
||||||
|
std::cout << "indirectly printing out the numbers from 0 to "
|
||||||
|
<< N << std::endl;
|
||||||
|
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||||
|
boost::make_indirect_iterator(pointers.end()),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
</pre>
|
||||||
|
The output is:
|
||||||
|
<pre>
|
||||||
|
indirectly printing out the numbers from 0 to 7
|
||||||
|
0 1 2 3 4 5 6
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><a name="counting_iterator_traits">Counting Iterator Traits</a></h2>
|
||||||
|
|
||||||
|
The counting iterator adaptor needs to determine the appropriate
|
||||||
|
<tt>difference_type</tt> and <tt>iterator_category</tt> to use based on the
|
||||||
|
<tt>Incrementable</tt> type supplied by the user. The
|
||||||
|
<tt>counting_iterator_traits</tt> class provides these types. If the
|
||||||
|
<tt>Incrementable</tt> type is an integral type or an iterator, these types
|
||||||
|
will be correctly deduced by the <tt>counting_iterator_traits</tt> provided by
|
||||||
|
the library. Otherwise, the user must specialize
|
||||||
|
<tt>counting_iterator_traits</tt> for her type or add nested typedefs to
|
||||||
|
her type to fulfill the needs of
|
||||||
|
<a href="http://www.sgi.com/tech/stl/iterator_traits.html">
|
||||||
|
<tt>std::iterator_traits</tt></a>.
|
||||||
|
|
||||||
|
<p>The following pseudocode describes how the <tt>counting_iterator_traits</tt> are determined:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
template <class Incrementable>
|
||||||
|
struct counting_iterator_traits
|
||||||
|
{
|
||||||
|
if (numeric_limits<Incrementable>::is_specialized) {
|
||||||
|
if (!numeric_limits<Incrementable>::is_integer)
|
||||||
|
COMPILE_TIME_ERROR;
|
||||||
|
|
||||||
|
if (!numeric_limits<Incrementable>::is_bounded
|
||||||
|
&& numeric_limits<Incrementable>::is_signed) {
|
||||||
|
typedef Incrementable difference_type;
|
||||||
|
}
|
||||||
|
else if (numeric_limits<Incrementable>::is_integral) {
|
||||||
|
typedef <i>next-larger-signed-type-or-intmax_t</i> difference_type;
|
||||||
|
}
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
} else {
|
||||||
|
typedef std::iterator_traits<Incrementable>::difference_type difference_type;
|
||||||
|
typedef std::iterator_traits<Incrementable>::iterator_category iterator_category;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The italicized sections above are implementation details, but it is important
|
||||||
|
to know that the <tt>difference_type</tt> for integral types is selected so that
|
||||||
|
it can always represent the difference between two values if such a built-in
|
||||||
|
integer exists. On platforms with a working <tt>std::numeric_limits</tt>
|
||||||
|
implementation, the <tt>difference_type</tt> for any variable-length signed
|
||||||
|
integer type <tt>T</tt> is <tt>T</tt> itself.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->26 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14386" --></p>
|
||||||
|
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
|
||||||
|
modify, sell and distribute this document is granted provided this copyright
|
||||||
|
notice appears in all copies. This document is provided "as is"
|
||||||
|
without express or implied warranty, and with no claim as to its suitability for
|
||||||
|
any purpose.</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
<!-- LocalWords: html charset alt gif hpp incrementable const namespace htm
|
||||||
|
-->
|
||||||
|
<!-- LocalWords: struct typename iostream int Siek CopyConstructible pre
|
||||||
|
-->
|
||||||
|
|
819
iterator_adaptors.htm
Normal file
819
iterator_adaptors.htm
Normal file
@@ -0,0 +1,819 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||||
|
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||||
|
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||||
|
<title>Header boost/iterator_adaptors.hpp Documentation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body bgcolor="#FFFFFF" text="#000000">
|
||||||
|
|
||||||
|
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||||
|
align="center" width="277" height="86">
|
||||||
|
|
||||||
|
<h1>Header
|
||||||
|
<a href="../../boost/pending/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||||
|
and
|
||||||
|
<a href="../../boost/pending/integer_range.hpp">boost/integer_range.hpp</a></h1>
|
||||||
|
|
||||||
|
<p>The file <tt>boost/iterator_adaptors.hpp</tt>
|
||||||
|
includes the main <tt>iterator_adaptors</tt> class and several other classes
|
||||||
|
for constructing commonly used iterator adaptors.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#iterator_adaptors"><tt>iterator_adaptors</tt></a>.
|
||||||
|
<li><a href="#iterator_adaptor"><tt>iterator_adaptor</tt></a>.
|
||||||
|
<li><a href="#transform_iterator"><tt>transform_iterator</tt></a>
|
||||||
|
<li><a href="#indirect_iterators"><tt>Indirect Iterator Adaptors</tt></a>
|
||||||
|
<li><a href="#projection_iterators"><tt>Projection Iterator Adaptors</tt></a>
|
||||||
|
<li><a href="#reverse_iterators"><tt>reverse_iterators</tt></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The file <tt>boost/integer_range.hpp</tt> includes a class that
|
||||||
|
uses iterator adaptors to create an iterator that increments over a
|
||||||
|
range of integers. The file also includes a "container" type
|
||||||
|
that creates a container-interface for the range of integers.
|
||||||
|
<ul>
|
||||||
|
<li><a href="#integer_range"><tt>integer_range</tt></a>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- put in something about Andrei Alexandrescu's contribution? -->
|
||||||
|
|
||||||
|
<p><a href="http://www.boost.org/people/dave_abrahams.htm">Dave
|
||||||
|
Abrahams</a> started the library, coming up with the idea to use
|
||||||
|
policy classes and how to handle the const/non-const iterator
|
||||||
|
interactions. He also contributed the <tt>indirect_iterators</tt> and
|
||||||
|
<tt>reverse_iterators</tt> classes.<br>
|
||||||
|
|
||||||
|
<a href="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</a>
|
||||||
|
contributed <tt>transform_iterator</tt>, <tt>integer_range</tt>,
|
||||||
|
and this documentation.<br>
|
||||||
|
|
||||||
|
<a href="http://www.boost.org/people/john_potter.htm">John Potter</a>
|
||||||
|
contributed <tt>indirect_iterator</tt> and <tt>projection_iterator</tt>
|
||||||
|
and made some simplifications to <tt>iterator_adaptor</tt>.
|
||||||
|
|
||||||
|
<h3><a name="iterator_adaptors">The Iterator Adaptors Class</a></h3>
|
||||||
|
|
||||||
|
Implementing standard conforming iterators is a non-trivial task.
|
||||||
|
There are some fine-points such as iterator/const_iterator
|
||||||
|
interactions and there are the myriad of operators that should be
|
||||||
|
implemented but are easily forgotten such as
|
||||||
|
<tt>operator->()</tt>. The purpose of the
|
||||||
|
<tt>iterator_adaptors</tt> class is to make it easier to implement an
|
||||||
|
iterator class, and even easier to extend and adapt existing iterator
|
||||||
|
types. The <tt>iterator_adaptors</tt> class itself is not an adaptor
|
||||||
|
class but a <i>type generator</i>. It generates a pair of adaptor classes,
|
||||||
|
one class for the mutable iterator and one class for the const
|
||||||
|
iterator. The definition of the <tt>iterator_adaptors</tt> class is as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator,
|
||||||
|
class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>,
|
||||||
|
class Policies = default_iterator_policies>
|
||||||
|
struct iterator_adaptors
|
||||||
|
{
|
||||||
|
typedef ... iterator;
|
||||||
|
typedef ... const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>The <tt>Iterator</tt> and <tt>ConstIterator</tt> template parameters
|
||||||
|
are the iterator types that you want to adapt. The <tt>Traits</tt> and
|
||||||
|
<tt>ConstTraits</tt> must be iterator traits classes. The traits
|
||||||
|
parameters default to the specialization of the
|
||||||
|
<tt>std::iterator_traits</tt> class for the adapted iterators. If you
|
||||||
|
want the traits for your new iterator adaptor (<tt>value_type</tt>,
|
||||||
|
<tt>iterator_category</tt>, etc.) to be the same as the adapted
|
||||||
|
iterator then use the default, otherwise create your own traits
|
||||||
|
classes and pass them in <a href="#1">[1]</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<p>The <tt>Policies</tt> class that you pass in will become the heart of
|
||||||
|
the iterator adaptor, supplying the core iterator operations that will determine how your new adaptor
|
||||||
|
class will behave. The core iterator operations are:
|
||||||
|
<ul>
|
||||||
|
<li><code>dereference</code> - returns an element of the iterator's <code>reference</code> type
|
||||||
|
<li><code>equal</code> - tests the iterator for equality
|
||||||
|
<li><code>increment</code> - increments the iterator
|
||||||
|
<li><code>decrement</code> - decrements bidirectional and random-access iterators
|
||||||
|
<li><code>less</code> - imposes a strict weak ordering relation on random-access iterators
|
||||||
|
<li><code>distance</code> - measures the distance between random-access iterators
|
||||||
|
<li><code>advance</code> - adds an integer offset to random-access iterators
|
||||||
|
</ul>
|
||||||
|
The <tt>Policies</tt> class must implement three, four, or
|
||||||
|
seven of the core iterator operations depending on whether you wish the
|
||||||
|
new iterator adaptor class to be a
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/ForwardIterator.html">
|
||||||
|
ForwardIterator</a>,
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/BidirectionalIterator.html">
|
||||||
|
BidirectionalIterator</a>, or <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||||
|
RandomAccessIterator</a>. The
|
||||||
|
<tt>iterator_category</tt> type of the traits class you pass in
|
||||||
|
must match the category of iterator that you want to create. The default
|
||||||
|
policy class, <tt>default_iterator_policies</tt>, implements all 7 of
|
||||||
|
the core operations in the usual way. If you wish to create an
|
||||||
|
iterator adaptor that only changes a few of the iterator's behaviors,
|
||||||
|
then you can have your new policy class inherit from
|
||||||
|
<tt>default_iterator_policies</tt> to avoid retyping the usual
|
||||||
|
behaviours. You should also look at <tt>default_iterator_policies</tt>
|
||||||
|
as the "boiler-plate" for your own policy classes. The
|
||||||
|
following is definition of the <tt>default_iterator_policies</tt>
|
||||||
|
class:
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct default_iterator_policies
|
||||||
|
{
|
||||||
|
// required for a ForwardIterator
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return *x; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
static void increment(Iterator& x)
|
||||||
|
{ ++x; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool equal(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x == y; }
|
||||||
|
|
||||||
|
// required for a BidirectionalIterator
|
||||||
|
template <class Iterator>
|
||||||
|
static void decrement(Iterator& x)
|
||||||
|
{ --x; }
|
||||||
|
|
||||||
|
// required for a RandomAccessIterator
|
||||||
|
template <class Iterator, class DifferenceType>
|
||||||
|
static void advance(Iterator& x, DifferenceType n)
|
||||||
|
{ x += n; }
|
||||||
|
|
||||||
|
template <class Difference, class Iterator1, class Iterator2>
|
||||||
|
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||||
|
{ return y - x; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool less(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x < y; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The generated iterator adaptor types will have the following
|
||||||
|
constructors.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
<i>iterator</i>(const Iterator& i, const Policies& p = Policies())
|
||||||
|
|
||||||
|
<i>const_iterator</i>(const ConstIterator& i, const Policies& p = Policies())
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<h3><a name="iterator_adaptor">The Iterator Adaptor Class</a></h3>
|
||||||
|
|
||||||
|
This is the class used inside of the <tt>iterator_adaptors</tt> type
|
||||||
|
generator. Use this class directly (instead of using
|
||||||
|
<tt>iterator_adaptors</tt>) when you are interested in creating only
|
||||||
|
one of the iterator types (either const or non-const) or when there is
|
||||||
|
no difference between the const and non-const versions of the iterator
|
||||||
|
type (often this is because there is only a const (read-only) version
|
||||||
|
of the iterator, as is the case for <tt>std::set</tt>'s iterators).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator,
|
||||||
|
class Policies = default_iterator_policies,
|
||||||
|
class Traits = std::iterator_traits<Iterator> >
|
||||||
|
struct iterator_adaptor;
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Next we will look at some iterator adaptors that are examples of how
|
||||||
|
to use the iterator adaptors class, and that are useful iterator
|
||||||
|
adaptors in their own right.
|
||||||
|
|
||||||
|
<h3><a name="transform_iterator">The Transform Iterator Class</a></h3>
|
||||||
|
|
||||||
|
It is often useful to automatically apply some function to the value
|
||||||
|
returned by dereferencing (<tt>operator*()</tt>) an iterator. The
|
||||||
|
<tt>transform_iterators</tt> class makes it easy to create an iterator
|
||||||
|
adaptor that does just that.
|
||||||
|
|
||||||
|
First let us consider what the <tt>Policies</tt> class for the transform
|
||||||
|
iterator should look like. We are only changing one of the iterator
|
||||||
|
behaviours, so we will inherit from
|
||||||
|
<tt>default_iterator_policies</tt>. In addition, we will need a
|
||||||
|
function object to apply, so we will have a template parameter and a
|
||||||
|
data member for the function object. The function will take one
|
||||||
|
argument (the dereferenced value) and we will need to know the
|
||||||
|
<tt>result_type</tt> of the function, so <a
|
||||||
|
href="http://www.sgi.com/Technology/STL/AdaptableUnaryFunction.html">
|
||||||
|
AdaptableUnaryFunction</a> is the corrent concept to choose for the
|
||||||
|
function object type. Now for the heart of our iterator adaptor, we
|
||||||
|
implement the <tt>dereference</tt> method, applying the function
|
||||||
|
object to <tt>*i</tt>. The <tt>type<Reference></tt> class is
|
||||||
|
there to tell you what the reference type of the iterator is, which is
|
||||||
|
handy when writing generic iterator adaptors such as this one <a
|
||||||
|
href="#2">[2]</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction>
|
||||||
|
struct transform_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
transform_iterator_policies() { }
|
||||||
|
transform_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
|
||||||
|
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& i) const
|
||||||
|
{ return m_f(*i); }
|
||||||
|
|
||||||
|
AdaptableUnaryFunction m_f;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Next we need to create the traits class for our new iterator. In some
|
||||||
|
situations you may need to create a separate traits class for the
|
||||||
|
const and non-const iterator types, but here a single traits class
|
||||||
|
will do. The <tt>value_type</tt> and <tt>reference</tt> type of our
|
||||||
|
transform iterator will be the <tt>result_type</tt> of the function
|
||||||
|
object. The <tt>difference_type</tt> and <tt>iterator_category</tt>
|
||||||
|
will be the same as the adapted iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class IteratorTraits>
|
||||||
|
struct transform_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef typename IteratorTraits::difference_type difference_type;
|
||||||
|
typedef typename IteratorTraits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
The final step is to use the <tt>iterator_adaptor</tt> class to
|
||||||
|
construct our transform iterator. We will use the single iterator
|
||||||
|
adaptor version because we will not need to create both a mutable and
|
||||||
|
const version of the transform iterator. The transform iterator is
|
||||||
|
inherently a read-only iterator. The nicest way to package up our new
|
||||||
|
transform iterator is to create a type generator similar to
|
||||||
|
<tt>iterator_adaptor</tt>. The first template parameter will be the
|
||||||
|
type of the function object. The second parameter will be the adapted
|
||||||
|
iterator type. The third parameter is the trait class for
|
||||||
|
the adapted iterator. Inside the <tt>transform_iterators</tt> class
|
||||||
|
we use the <tt>transform_iterator_traits</tt> class defined above to
|
||||||
|
create the traits class for the new transform iterator. We then use
|
||||||
|
the <tt>iterator_adaptor</tt> class to extract the generated
|
||||||
|
iterator adaptor type.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction,
|
||||||
|
class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct transform_iterator
|
||||||
|
{
|
||||||
|
typedef transform_iterator_traits<AdaptableUnaryFunction,Traits>
|
||||||
|
TransTraits;
|
||||||
|
typedef iterator_adaptor<Iterator, TransTraits,
|
||||||
|
transform_iterator_policies<AdaptableUnaryFunction> >::type type;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following is a simple example of how to use the
|
||||||
|
<tt>transform_iterators</tt> class to iterate through a range of
|
||||||
|
numbers, multiplying each of them by 2 when they are dereferenced.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/iterator_adaptors.hpp>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
|
||||||
|
typedef std::binder1st< std::multiplies<int> > Function;
|
||||||
|
typedef boost::transform_iterator<Function, int*,
|
||||||
|
boost::iterator<std::random_access_iterator_tag, int>
|
||||||
|
>::type doubling_iterator;
|
||||||
|
|
||||||
|
doubling_iterator i(x, std::bind1st(std::multiplies<int>(), 2)),
|
||||||
|
i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies<int>(), 2));
|
||||||
|
|
||||||
|
std::cout << "multiplying the array by 2:" << std::endl;
|
||||||
|
while (i != i_end)
|
||||||
|
std::cout << *i++ << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="indirect_iterators">The Indirect Iterator Adaptors</a></h3>
|
||||||
|
|
||||||
|
It is not all that uncommon to create data structures that consist of
|
||||||
|
pointers to pointers. For such a structure it might be nice to have an
|
||||||
|
iterator that applies a double-dereference inside the
|
||||||
|
<tt>operator*()</tt>. The implementation of this is similar to the
|
||||||
|
<tt>transform_iterators</tt><a href="#3">[3]</a>. When talking about a
|
||||||
|
data structure of pointers to pointers (or more generally, iterators
|
||||||
|
to iterators), we call the first level iterators the <i>outer</i>
|
||||||
|
iterators and the second level iterators the <i>inner</i>
|
||||||
|
iterators. For example, if the outer iterator type is <tt>T**</tt>
|
||||||
|
then the inner iterator type is <tt>T*</tt>.
|
||||||
|
|
||||||
|
To implement the indirect adaptors, we first create a policies class
|
||||||
|
which does a double-dereference in the <tt>dereference()</tt> method.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct indirect_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return **x; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
We then create a traits class, including a template parameter for both
|
||||||
|
the inner and outer iterators and traits classes. The
|
||||||
|
<tt>difference_type</tt> and <tt>iterator_category</tt> come from the
|
||||||
|
outer iterator, while the <tt>value_type</tt>, <tt>pointer</tt>, and
|
||||||
|
<tt>reference</tt> types come from the inner iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class OuterIterator, class InnerIterator,
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_traits
|
||||||
|
{
|
||||||
|
typedef typename OuterTraits::difference_type difference_type;
|
||||||
|
typedef typename InnerTraits::value_type value_type;
|
||||||
|
typedef typename InnerTraits::pointer pointer;
|
||||||
|
typedef typename InnerTraits::reference reference;
|
||||||
|
typedef typename OuterTraits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Lastly we wrap this up in two type generators:
|
||||||
|
<tt>indirect_iterator</tt> for creating a single indirect iterator
|
||||||
|
type, and <tt>indirect_iterators</tt> for creating an const/non-const
|
||||||
|
pair of indirect iterator types. We use the <tt>iterator_adaptor</tt>
|
||||||
|
and <tt>iterator_adaptors</tt> classes here to do most of the work.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class OuterIterator, class InnerIterator,
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_iterator
|
||||||
|
{
|
||||||
|
typedef iterator_adaptor<OuterIterator,
|
||||||
|
indirect_iterator_policies,
|
||||||
|
indirect_traits<OuterIterator, InnerIterator,
|
||||||
|
OuterTraits, InnerTraits>
|
||||||
|
> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class OuterIterator, // Mutable or Immutable, does not matter
|
||||||
|
class InnerIterator, // Mutable
|
||||||
|
class ConstInnerIterator, // Immutable
|
||||||
|
class OuterTraits = std::iterator_traits<OuterIterator>,
|
||||||
|
class InnerTraits = std::iterator_traits<InnerIterator>,
|
||||||
|
class ConstInnerTraits = std::iterator_traits<ConstInnerIterator>
|
||||||
|
>
|
||||||
|
struct indirect_iterators
|
||||||
|
{
|
||||||
|
typedef iterator_adaptors<OuterIterator, OuterIterator,
|
||||||
|
indirect_traits<OuterIterator, InnerIterator,
|
||||||
|
OuterTraits, InnerTraits>,
|
||||||
|
indirect_traits<OuterIterator, ConstInnerIterator,
|
||||||
|
OuterTraits, ConstInnerTraits>,
|
||||||
|
indirect_iterator_policies
|
||||||
|
> Adaptors;
|
||||||
|
typedef typename Adaptors::iterator iterator;
|
||||||
|
typedef typename Adaptors::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="projection_iterators">The Projection Iterator Adaptors</a></h3>
|
||||||
|
|
||||||
|
The projection iterator adaptor is very similar to the transform
|
||||||
|
iterator, except for a subtle difference in the return type: the
|
||||||
|
tranform iterator returns the result of the unary function by value,
|
||||||
|
whereas the projection iterator returns the result by reference.
|
||||||
|
Therefore, these two adaptors cater to different kinds of unary
|
||||||
|
functions. Transform iterator caters to functions that create new
|
||||||
|
objects, whereas projection iterator caters to a function that somehow
|
||||||
|
obtains a reference to an object that already exists. An example of a
|
||||||
|
unary function that is suitable for use with the projection adaptor is
|
||||||
|
<tt>select1st_</tt>:
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Pair>
|
||||||
|
struct select1st_
|
||||||
|
: public std::unary_function<Pair, typename Pair::first_type>
|
||||||
|
{
|
||||||
|
const typename Pair::first_type& operator()(const Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
typename Pair::first_type& operator()(Pair& x) const {
|
||||||
|
return x.first;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
The implementation of projection iterator is as follows. First, the
|
||||||
|
policies class is the same as the transform iterator's policies class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction>
|
||||||
|
struct projection_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
projection_iterator_policies() { }
|
||||||
|
projection_iterator_policies(const AdaptableUnaryFunction& f) : m_f(f) { }
|
||||||
|
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference (type<Reference>, Iterator const& iter) const {
|
||||||
|
return m_f(*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdaptableUnaryFunction m_f;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Next we have two traits classes. We use <tt>value_type&</tt> for the
|
||||||
|
reference type of the mutable projection iterator, and <tt>const
|
||||||
|
value_type&</tt> for the immutable projection iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class Traits>
|
||||||
|
struct projection_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type& reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef typename Traits::difference_type difference_type;
|
||||||
|
typedef typename Traits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Traits>
|
||||||
|
struct const_projection_iterator_traits {
|
||||||
|
typedef typename AdaptableUnaryFunction::result_type value_type;
|
||||||
|
typedef value_type const& reference;
|
||||||
|
typedef value_type const* pointer;
|
||||||
|
typedef typename Traits::difference_type difference_type;
|
||||||
|
typedef typename Traits::iterator_category iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
And to finish up, we create three generator classes that
|
||||||
|
use <tt>iterator_adaptor</tt> to create the projection iterator
|
||||||
|
types. The class <tt>projection_iterator</tt> creates a mutable
|
||||||
|
projection iterator type. The class <tt>const_projection_iterator</tt>
|
||||||
|
creates an immutable projection iterator type, and
|
||||||
|
<tt>projection_iterators</tt> creates both mutable and immutable
|
||||||
|
projection iterator types.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct projection_iterator {
|
||||||
|
typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
|
||||||
|
Projection_Traits;
|
||||||
|
typedef iterator_adaptor<Iterator,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction>,
|
||||||
|
Projection_Traits> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>
|
||||||
|
>
|
||||||
|
struct const_projection_iterator {
|
||||||
|
typedef const_projection_iterator_traits<AdaptableUnaryFunction,
|
||||||
|
Traits> Projection_Traits;
|
||||||
|
typedef iterator_adaptor<Iterator,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction>,
|
||||||
|
Projection_Traits> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AdaptableUnaryFunction, class Iterator, class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>
|
||||||
|
>
|
||||||
|
struct projection_iterators {
|
||||||
|
typedef projection_iterator_traits<AdaptableUnaryFunction, Traits>
|
||||||
|
Projection_Traits;
|
||||||
|
typedef const_projection_iterator_traits<AdaptableUnaryFunction,
|
||||||
|
ConstTraits> Const_Projection_Traits;
|
||||||
|
typedef iterator_adaptors<Iterator, ConstIterator,
|
||||||
|
Projection_Traits, Const_Projection_Traits,
|
||||||
|
projection_iterator_policies<AdaptableUnaryFunction> > Adaptors;
|
||||||
|
typedef typename Adaptors::iterator iterator;
|
||||||
|
typedef typename Adaptors::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="reverse_iterators">The Reverse Iterators Class</a></h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Yes, there is already a <tt>reverse_iterator</tt> adaptor class
|
||||||
|
defined in the C++ Standard, but using the <tt>iterator_adaptors</tt>
|
||||||
|
class we can re-implement this classic adaptor in a more succinct and
|
||||||
|
elegant fashion. Also, this makes for a good example of using
|
||||||
|
<tt>iterator_adaptors</tt> that is in familiar territory.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The first step is to create the <tt>Policies</tt> class. As in the
|
||||||
|
<tt>std::reverse_iterator</tt> class, we need to flip all the
|
||||||
|
operations of the iterator. Increment will become decrement, advancing
|
||||||
|
by <tt>n</tt> will become retreating by <tt>n</tt>, etc.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
struct reverse_iterator_policies
|
||||||
|
{
|
||||||
|
template <class Reference, class Iterator>
|
||||||
|
Reference dereference(type<Reference>, const Iterator& x) const
|
||||||
|
{ return *boost::prior(x); }
|
||||||
|
// this is equivalent to { Iterator tmp = x; return *--tmp; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
void increment(Iterator& x) const
|
||||||
|
{ --x; }
|
||||||
|
|
||||||
|
template <class Iterator>
|
||||||
|
void decrement(Iterator& x) const
|
||||||
|
{ ++x; }
|
||||||
|
|
||||||
|
template <class Iterator, class DifferenceType>
|
||||||
|
void advance(Iterator& x, DifferenceType n) const
|
||||||
|
{ x -= n; }
|
||||||
|
|
||||||
|
template <class Difference, class Iterator1, class Iterator2>
|
||||||
|
Difference distance(type<Difference>, Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x - y; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool equal(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return x == y; }
|
||||||
|
|
||||||
|
template <class Iterator1, class Iterator2>
|
||||||
|
bool less(Iterator1& x, Iterator2& y) const
|
||||||
|
{ return y < x; }
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Since the traits of the reverse iterator adaptor will be the same as
|
||||||
|
the adapted iterator's traits, we do not need to create new traits
|
||||||
|
classes as was the case for <tt>transform_iterator</tt>. We can skip to
|
||||||
|
the final stage of creating a type generator class for our reverse
|
||||||
|
iterators using the <tt>iterator_adaptor</tt> class.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class Iterator, class ConstIterator,
|
||||||
|
class Traits = std::iterator_traits<Iterator>,
|
||||||
|
class ConstTraits = std::iterator_traits<ConstIterator>
|
||||||
|
>
|
||||||
|
struct reverse_iterators
|
||||||
|
{
|
||||||
|
typedef iterator_adaptors<Iterator,ConstIterator,Traits,ConstTraits,
|
||||||
|
reverse_iterator_policies> Adaptor;
|
||||||
|
typedef typename Adaptor::iterator iterator;
|
||||||
|
typedef typename Adaptor::const_iterator const_iterator;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
A typical use of the <tt>reverse_iterators</tt> class is in
|
||||||
|
user-defined container types. You can use the
|
||||||
|
<tt>reverse_iterators</tt> class to generate the reverse iterators for
|
||||||
|
your container.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
class my_container {
|
||||||
|
...
|
||||||
|
typedef ... iterator;
|
||||||
|
typedef ... const_iterator;
|
||||||
|
|
||||||
|
typedef reverse_iterators<iterator, const_iterator> RevIters;
|
||||||
|
typedef typename RevIters::iterator reverse_iterator;
|
||||||
|
typedef typename RevIters::const_iterator const_reverse_iterator;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a name="integer_range">The Integer Range Class</a></h3>
|
||||||
|
|
||||||
|
The <tt>iterator_adaptors</tt> class can not only be used for adapting
|
||||||
|
iterators, but it can also be used to take a non-iterator type and use
|
||||||
|
it to build an iterator. An especially simple example of this is
|
||||||
|
turning an integer type into an iterator, a counting iterator. The
|
||||||
|
builtin integer types of C++ are almost iterators. They have
|
||||||
|
<tt>operator++()</tt>, <tt>operator--()</tt>, etc. The one operator
|
||||||
|
they are lacking is the <tt>operator*()</tt>, which we will want to
|
||||||
|
simply return the current value of the integer. The following few
|
||||||
|
lines of code implement the policy and traits class for the counting
|
||||||
|
iterator.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class IntegerType>
|
||||||
|
struct counting_iterator_policies : public default_iterator_policies
|
||||||
|
{
|
||||||
|
IntegerType dereference(type<IntegerType>, const IntegerType& i) const
|
||||||
|
{ return i; }
|
||||||
|
};
|
||||||
|
template <class IntegerType>
|
||||||
|
struct counting_iterator_traits {
|
||||||
|
typedef IntegerType value_type;
|
||||||
|
typedef IntegerType reference;
|
||||||
|
typedef value_type* pointer;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
Typically we will want to count the integers in some range, so a nice
|
||||||
|
interface would be to have a fake container that represents the range
|
||||||
|
of integers. The following is the definition of such a class called
|
||||||
|
<tt>integer_range</tt>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
template <class IntegerType>
|
||||||
|
struct integer_range {
|
||||||
|
typedef typename iterator_adaptor<IntegerType,
|
||||||
|
counting_iterator_traits<IntegerType>,
|
||||||
|
counting_iterator_policies >::type iterator;
|
||||||
|
typedef iterator const_iterator;
|
||||||
|
typedef IntegerType value_type;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef IntegerType reference;
|
||||||
|
typedef IntegerType* pointer;
|
||||||
|
typedef IntegerType size_type;
|
||||||
|
|
||||||
|
integer_range(IntegerType start, IntegerType finish)
|
||||||
|
: m_start(start), m_finish(finish) { }
|
||||||
|
|
||||||
|
iterator begin() const { return iterator(m_start); }
|
||||||
|
iterator end() const { return iterator(m_finish); }
|
||||||
|
size_type size() const { return m_finish - m_start; }
|
||||||
|
bool empty() const { return m_finish == m_start; }
|
||||||
|
void swap(integer_range& x) {
|
||||||
|
std::swap(m_start, x.m_start);
|
||||||
|
std::swap(m_finish, x.m_finish);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
IntegerType m_start, m_finish;
|
||||||
|
};
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following is an example of how to use the
|
||||||
|
<tt>integer_range</tt> class to count from 0 to 4.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 COLS=2>
|
||||||
|
<TR><TD WIDTH=30 VALIGN=TOP></TD><TD>
|
||||||
|
<PRE>
|
||||||
|
boost::integer_range<int> r(0,5);
|
||||||
|
|
||||||
|
cout << "counting to from 0 to 4:" << endl;
|
||||||
|
std::copy(r.begin(), r.end(), ostream_iterator<int>(cout, " "));
|
||||||
|
cout << endl;
|
||||||
|
</PRE></TD></TABLE>
|
||||||
|
|
||||||
|
<h3>Challenge</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There is an unlimited number of ways the the
|
||||||
|
<tt>iterator_adaptors</tt> class can be used to create iterators. One
|
||||||
|
interesting exercise would be to re-implement the iterators of
|
||||||
|
<tt>std::list</tt> and <tt>std::slist</tt> using
|
||||||
|
<tt>iterator_adaptors</tt>, where the adapted <tt>Iterator</tt> types
|
||||||
|
would be node pointers.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Notes</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="1">[1]</a>
|
||||||
|
If your compiler does not support partial specialization and hence
|
||||||
|
does not have a working <tt>std::iterator_traits</tt> class, you will
|
||||||
|
not be able to use the defaults and will need to supply your own
|
||||||
|
<tt>Traits</tt> and <tt>ConstTraits</tt> classes.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="2">[2]</a>
|
||||||
|
The reference type could also be obtained from
|
||||||
|
<tt>std::iterator_traits</tt>, but that is not portable on compilers
|
||||||
|
that do not support partial specialization.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a name="3">[3]</a>
|
||||||
|
It would have been more elegant to implement <tt>indirect_iterators</tt>
|
||||||
|
using <tt>transform_iterators</tt>, but for subtle reasons that would require
|
||||||
|
the use of <tt>boost::remove_cv</tt> which is not portable.
|
||||||
|
|
||||||
|
<h3>Implementation Notes</h3>
|
||||||
|
|
||||||
|
The code is somewhat complicated because there are three iterator
|
||||||
|
adaptor class: <tt>forward_iterator_adaptor</tt>,
|
||||||
|
<tt>bidirectional_iterator_adaptor</tt>, and
|
||||||
|
<tt>random_access_iterator_adaptor</tt>. The alternative would be to
|
||||||
|
just have one iterator adaptor equivalent to the
|
||||||
|
<tt>random_access_iterator_adaptor</tt>. The reason for going with
|
||||||
|
the three adaptors is that according to 14.5.3p5 in the C++ Standard,
|
||||||
|
friend functions defined inside a template class body are instantiated
|
||||||
|
when the template class is instantiated. This means that if we only
|
||||||
|
used the one iterator adaptor, then if the adapted iterator did not
|
||||||
|
meet all of the requirements for a
|
||||||
|
<a href="http://www.sgi.com/Technology/STL/RandomAccessIterator.html">
|
||||||
|
RandomAccessIterator</a> then a compiler error should occur. Many
|
||||||
|
current compilers in fact do not instantiate the friend functions
|
||||||
|
unless used, so we could get away with the one iterator adaptor in
|
||||||
|
most cases. However, out of respect for the standard this implementation
|
||||||
|
uses the three adaptors.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->27 Nov 2000<!--webbot bot="Timestamp" endspan i-checksum="15248" --></p>
|
||||||
|
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
|
||||||
|
modify, sell and distribute this document is granted provided this copyright
|
||||||
|
notice appears in all copies. This document is provided "as is"
|
||||||
|
without express or implied warranty, and with no claim as to its suitability for
|
||||||
|
any purpose.</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
Reference in New Issue
Block a user