From b70ad177bbee6009d7c403f5aeb1cd4327a351ed Mon Sep 17 00:00:00 2001 From: Jeremy Siek Date: Mon, 18 Sep 2000 16:00:39 +0000 Subject: [PATCH] new documentation [SVN r7721] --- CopyConstructible.html | 188 ++++++++++ iterator_adaptor_examples.cpp | 45 +++ iterator_adaptors.htm | 629 ++++++++++++++++++++++++++++++++++ tie.html | 138 ++++++++ tie_example.cpp | 61 ++++ 5 files changed, 1061 insertions(+) create mode 100644 CopyConstructible.html create mode 100644 iterator_adaptor_examples.cpp create mode 100644 iterator_adaptors.htm create mode 100644 tie.html create mode 100644 tie_example.cpp diff --git a/CopyConstructible.html b/CopyConstructible.html new file mode 100644 index 0000000..43bd843 --- /dev/null +++ b/CopyConstructible.html @@ -0,0 +1,188 @@ + + + +CopyConstructible + + +C++ Boost + +
+

CopyConstructible

+ +

Description

+A type is CopyConstructible if it is possible to copy objects of that +type. + +

Notation

+ + + + + + + + + + + + + + + + +
+T + +is type that is a model of CopyConstructible +
+t + +is an object of type T +
+u + +is an object of type const T +
+

Definitions

+

Valid expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+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 +
+ + + +

Models

+ + + +

See also

+DefaultConstructible +and +Assignable + +
+
+ + +
Copyright © 2000 +Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + + diff --git a/iterator_adaptor_examples.cpp b/iterator_adaptor_examples.cpp new file mode 100644 index 0000000..aa0affb --- /dev/null +++ b/iterator_adaptor_examples.cpp @@ -0,0 +1,45 @@ +// (C) Copyright Jeremy Siek 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. + + +#include +#include +#include +#include + +int +main(int, char*[]) +{ + // This is a simple example of using the transform_iterators class to + // generate iterators that multiply the value returned by dereferencing + // the iterator. In this case we are multiplying by 2. + + int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + typedef std::binder1st< std::multiplies > Function; + typedef boost::transform_iterator + >::type doubling_iterator; + + doubling_iterator i(x, std::bind1st(std::multiplies(), 2)), + i_end(x + sizeof(x)/sizeof(int), std::bind1st(std::multiplies(), 2)); + + std::cout << "multiplying the array by 2:" << std::endl; + while (i != i_end) + std::cout << *i++ << " "; + std::cout << std::endl; + + // Here is an example of counting from 0 to 5 using the integer_range class. + + boost::integer_range r(0,5); + + std::cout << "counting to from 0 to 4:" << std::endl; + std::copy(r.begin(), r.end(), std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + + return 0; +} + + diff --git a/iterator_adaptors.htm b/iterator_adaptors.htm new file mode 100644 index 0000000..19d78d9 --- /dev/null +++ b/iterator_adaptors.htm @@ -0,0 +1,629 @@ + + + + + + +Header boost/iterator_adaptors.hpp Documentation + + + + +c++boost.gif (8819 bytes) + +

Header +boost/iterator_adaptors.hpp

+ +

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. + +

The Iterator Adaptors Class

+ +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 +operator->(). The purpose of the +iterator_adaptors class is to make it easier to implement an +iterator class, and even easier to extend and adapt existing iterator +types. The iterator_adaptors class itself is not an adaptor +class but a type generator. It generates a pair of adaptor classes, +one class for the mutable iterator and one class for the const +iterator. The definition of the iterator_adaptors class is as +follows: + +

+ +
+
+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())
+
+ +

The Iterator Adaptor Class

+ +This is the class used inside of the iterator_adaptors type +generator. Use this class directly (instead of using +iterator_adaptors) 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 std::set's iterators. Use the same type for +the Iterator and NonconstIterator template +arguments. + +

+ +
+
+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. + +

The Transform Iterator Class

+ +It is often useful to automatically apply some function to the value +returned by dereferencing (operator*()) an iterator. The +transform_iterators class makes it easy to create an iterator +adaptor that does just that. + +First let us consider what the Policies class for the transform +iterator should look like. We are only changing one of the iterator +behaviours, so we will inherit from +default_iterator_policies. 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 +result_type of the function, so +AdaptableUnaryFunction is the corrent concept to choose for the +function object type. Now for the heart of our iterator adaptor, we +implement the dereference method, applying the function +object to *i. The type<Reference> 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 [2]. + + +

+ +
+
+  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;
+  };
+
+ +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 value_type and reference type of our +transform iterator will be the result_type of the function +object. The difference_type and iterator_category +will be the same as the adapted iterator. + +

+ +
+
+  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;
+  };
+
+ +The final step is to use the iterator_adaptor 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 +iterator_adaptor. 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 transform_iterators class +we use the transform_iterator_traits class defined above to +create the traits class for the new transform iterator. We then use +the iterator_adaptor class to extract the generated +iterator adaptor type. + +

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

The Indirect Iterators Class

+ +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 +operator*(). The implementation of this is similar to the +transform_iterators[3]. We first create a +policies class which does a double-dereference in the +dereference() method. We then create a traits class, this +time also including a template parameter for the traits of the second +level iterators as well as the first. Lastly we wrap this up in the +type generator indirect_iterators, using +iterator_adaptors to do most of the work. + +

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

The Reverse Iterators Class

+ +

+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; }
+};
+
+ +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 transform_iterator. We can skip to +the final stage of creating a type generator class for our reverse +iterators using the iterator_adaptor class. + +

+ +
+
+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;
+};
+
+ +A typical use of the reverse_iterators class is in +user-defined container types. You can use the +reverse_iterators class to generate the reverse iterators for +your container. + +

+ +
+
+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;
+  ...
+};
+
+ + +

The Integer Range Class

+ +The iterator_adaptors 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 +operator++(), operator--(), etc. The one operator +they are lacking is the operator*(), 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. + +

+ +
+
+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;
+};
+
+ +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 +integer_range. + +

+ +
+
+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;
+
+ +

Challenge

+ +

+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. + + +

Notes

+ +

+[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. + +

Implementation Notes

+ +The code is somewhat complicated because there are three iterator +adaptor class: forward_iterator_adaptor, +bidirectional_iterator_adaptor, and +random_access_iterator_adaptor. The alternative would be to +just have one iterator adaptor equivalent to the +random_access_iterator_adaptor. 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 + +RandomAccessIterator 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. + + + +
+

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 @@ + + + +Boost Tie + +C++ Boost + +
+ +

+tie +

+ +

+

+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]. + +

+ +

Where Defined

+ +

+boost/utility.hpp + +

+ +

Example

+ +

+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) +
+ + + diff --git a/tie_example.cpp b/tie_example.cpp new file mode 100644 index 0000000..54a81af --- /dev/null +++ b/tie_example.cpp @@ -0,0 +1,61 @@ +// (C) Copyright Jeremy Siek 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. +// +// This is an example demonstrating how to use the tie() function. +// The purpose of tie() is to make it easiery to deal with std::pair +// return values. +// +// Contributed by Jeremy Siek +// +// Sample output +// +// 3 successfully inserted. +// 9 was already in the set. +// There were 2 occurances of 4. + +#include +#include +#include +#include + +int +main(int, char*[]) +{ + { + typedef std::set 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 + + 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 + + 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; +}