diff --git a/CopyConstructible.html b/CopyConstructible.html new file mode 100644 index 0000000..43bd843 --- /dev/null +++ b/CopyConstructible.html @@ -0,0 +1,188 @@ + + +
++T + | ++is type that is a model of CopyConstructible + | +
+t + | ++is an object of type T + | +
+u + | ++is an object of type const T + | +
+Name + | ++Expression + | ++Return type + | ++Semantics + | +
---|---|---|---|
+Copy constructor + | ++T(t) + | ++T + | ++t is equivalent to T(t) + | +
+Copy constructor + | +
++T(u) ++ |
++T + | ++u is equivalent to T(u) + | +
+Destructor + | +
++t.~T() ++ |
++T + | ++ + | +
+Address Operator + | +
++&t ++ |
++T* + | ++denotes the address of t + | +
+Address Operator + | +
++&u ++ |
++T* + | ++denotes the address of u + | +
Copyright © 2000 | +Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) + |
The file boost/iterator_adaptors.hpp +includes the main iterator_adaptors class and several other classes +for constructing commonly used iterator adaptors.
+ +Dave
+Abrahams 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 indirect_iterators and
+reverse_iterators classes.
+
+Jeremy Siek
+contributed transform_iterator, integer_range,
+and this documentation.
+
+
+
++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; +}; + |
The Iterator and ConstIterator template parameters +are the iterator types that you want to adapt. The Traits and +ConstTraits must be iterator traits classes. The traits +parameters default to the specialization of the +std::iterator_traits class for the adapted iterators. If you +want the traits for your new iterator adaptor (value_type, +iterator_category, etc.) to be the same as the adapted +iterator then use the default, otherwise create your own traits +classes and pass them in [1]. + + +
The Policies class that you pass in will become the heart of +the iterator adaptor. The policy class determines how your new adaptor +class will behave. The Policies class must implement 3, 4, or +7 of the core iterator operations depending on whether you wish the +new iterator adaptor class to be a + +ForwardIterator, + +BidirectionalIterator, or +RandomAccessIterator. Make sure that the +iterator_category type of the traits class you pass in +matches the category of iterator that you want to create. The default +policy class, default_iterator_policies, 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 +default_iterator_policies to avoid retyping the usual +behaviours. You should also look at default_iterator_policies +as the "boiler-plate" for your own policy classes. The +following is definition of the default_iterator_policies +class: + + +
+
++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> + void increment(Iterator& x) const + { ++x; } + + template <class Iterator1, class Iterator2> + bool equal(Iterator1& x, Iterator2& y) const + { return x == y; } + + // required for a BidirectionalIterator + template <class Iterator> + void decrement(Iterator& x) const + { --x; } + + // required for a RandomAccessIterator + 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 y - x; } + + template <class Iterator1, class Iterator2> + bool less(Iterator1& x, Iterator2& y) const + { return x < y; } +}; + |
+The generated iterator adaptor types will have the following +constructors. + +
+
++iterator(const Iterator& i, const Policies& p = Policies()) + +const_iterator(const ConstIterator& i, const Policies& p = Policies()) + |
+
++template <class Iterator, + class Policies = default_iterator_policies, + class NonconstIterator = Iterator, + class Traits = std::iterator_traits<Iterator> > +struct iterator_adaptor; + |
+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. + +
+
++ template <class AdaptableUnaryFunction> + struct transform_iterator_policies : public default_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; + }; + |
+
++ 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; + }; + |
+
++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; +}; + |
+The following is a simple example of how to use the +transform_iterators class to iterate through a range of +numbers, multiplying each of them by 2 when they are dereferenced. + +
+
++#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; +} + |
+
++ struct indirect_iterator_policies : public default_iterator_policies + { + template <class Reference, class Iterator> + Reference dereference(type<Reference>, const Iterator& x) const + { return **x; } + }; + + template <class IndirectIterator, + class IndirectTraits = std::iterator_traits<IndirectIterator>, + class Traits = + std::iterator_traits<typename IndirectTraits::value_type> + > + struct indirect_traits + { + typedef typename IndirectTraits::difference_type difference_type; + typedef typename Traits::value_type value_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef typename IndirectTraits::iterator_category iterator_category; + }; + + template <class IndirectIterator, class ConstIndirectIterator, + class IndirectTraits = + std::iterator_traits<IndirectIterator>, + class ConstIndirectTraits = + std::iterator_traits<ConstIndirectIterator>, + class Traits = + std::iterator_traits<typename IndirectTraits::value_type> + > + struct indirect_iterators + { + typedef typename IndirectTraits::value_type Iterator; + typedef typename Traits::value_type ValueType; + typedef iterator_adaptors<IndirectIterator, ConstIndirectIterator, + indirect_traits<IndirectIterator, IndirectTraits, Traits>, + indirect_traits<ConstIndirectIterator, ConstIndirectTraits, Traits>, + indirect_iterator_policies + > Adaptors; + typedef typename Adaptors::iterator iterator; + typedef typename Adaptors::const_iterator const_iterator; + }; + |
+Yes, there is already a reverse_iterator adaptor class +defined in the C++ Standard, but using the iterator_adaptors +class we can re-implement this classic adaptor in a more succinct and +elegant fashion. Also, this makes for a good example of using +iterator_adaptors that is in familiar territory. + +
+The first step is to create the Policies class. As in the +std::reverse_iterator class, we need to flip all the +operations of the iterator. Increment will become decrement, advancing +by n will become retreating by n, etc. + +
+
++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; } +}; + |
+
++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; +}; + |
+
++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; + ... +}; + |
+
++struct counting_iterator_policies : public default_iterator_policies +{ + template <class IntegerType> + 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; +}; + |
+
++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; +}; + |
+The following is an example of how to use the +integer_range class to count from 0 to 4. + +
+
++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; + |
+There is an unlimited number of ways the the +iterator_adaptors class can be used to create iterators. One +interesting exercise would be to re-implement the iterators of +std::list and std::slist using +iterator_adaptors, where the adapted Iterator types +would be node pointers. + + +
+[1] +If your compiler does not support partial specialization and hence +does not have a working std::iterator_traits class, you will +not be able to use the defaults and will need to supply your own +Traits and ConstTraits classes. + +
+[2] +The reference type could also be obtained from +std::iterator_traits, but that is not portable on compilers +that do not support partial specialization. + +
+[3] +It would have been more elegant to implement indirect_iterators +using transform_iterators, but for subtle reasons that would require +the use of boost::remove_cv which is not portable. + +
Revised 17 Jun 2000
+© 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.
+ + + + diff --git a/tie.html b/tie.html new file mode 100644 index 0000000..a583f84 --- /dev/null +++ b/tie.html @@ -0,0 +1,138 @@ + + + ++
+template <class A, class B> +tied<A,B> tie(A& a, B& b); ++ +
+This is a utility function that makes it more convenient to work with +a function which returns a pair. The effect of the tie() +function is to allow the assignment of the two values of the pair to +two separate variables. The idea for this comes from Jaakko +Järvi's Binders [1]. + +
+ +
+boost/utility.hpp + +
+ +
+An example of using the tie() function with the +vertices() function, which returns a pair of +type std::pair<vertex_iterator,vertex_iterator>. The +pair of iterators is assigned to the iterator variables i and +end. + +
+
+ graph_traits< adjacency_list<> >::vertex_iterator i, end; + for(tie(i,end) = vertices(G); i != end; ++i) + // ... ++ +
+Here is another example that uses tie() for handling +operaitons with std::set. + +
+
+#include <set> +#include <algorithm> +#include <iostream> +#include <boost/utility.hpp> + +int +main(int, char*[]) +{ + { + typedef std::set<int> SetT; + SetT::iterator i, end; + bool inserted; + + int vals[5] = { 5, 2, 4, 9, 1 }; + SetT s(vals, vals + 5); + + // Using tie() with a return value of pair<iterator,bool> + + int new_vals[2] = { 3, 9 }; + + for (int k = 0; k < 2; ++k) { + boost::tie(i,inserted) = s.insert(new_vals[k]); + if (!inserted) + std::cout << *i << " was already in the set." << std::endl; + else + std::cout << *i << " successfully inserted." << std::endl; + } + } + { + int* i, *end; + int vals[6] = { 5, 2, 4, 4, 9, 1 }; + std::sort(vals, vals + 6); + + // Using tie() with a return value of pair<iterator,iterator> + + boost::tie(i,end) = std::equal_range(vals, vals + 6, 4); + std::cout << "There were " << std::distance(i,end) + << " occurances of " << *i << "." << std::endl; + // Footnote: of course one would normally just use std::count() + // to get this information, but that would spoil the example :) + } + return 0; +} ++The output is: +
+ 3 successfully inserted. + 9 was already in the set. + There were 2 occurances of 4. ++ +
Copyright © 2000 |
+Jeremy Siek,
+Univ.of Notre Dame (jsiek@lsc.nd.edu) +Lie-Quan Lee, Univ.of Notre Dame (llee1@lsc.nd.edu) +Andrew Lumsdaine, +Univ.of Notre Dame (lums@lsc.nd.edu) + |