diff --git a/concept_tests.cpp b/concept_tests.cpp new file mode 100644 index 0000000..f75f311 --- /dev/null +++ b/concept_tests.cpp @@ -0,0 +1,73 @@ +#include +#include + +struct new_iterator + : public boost::iterator, + public boost::new_iterator_base +{ + typedef boost::random_access_traversal_tag traversal_category; + typedef boost::mutable_lvalue_iterator_tag return_category; + + int& operator*() const { return *m_x; } + new_iterator& operator++() { return *this; } + new_iterator operator++(int) { return *this; } + new_iterator& operator--() { return *this; } + new_iterator operator--(int) { return *this; } + new_iterator& operator+=(std::ptrdiff_t) { return *this; } + new_iterator operator+(std::ptrdiff_t) { return *this; } + new_iterator& operator-=(std::ptrdiff_t) { return *this; } + std::ptrdiff_t operator-(const new_iterator&) const { return 0; } + new_iterator operator-(std::ptrdiff_t) const { return *this; } + bool operator==(const new_iterator&) const { return false; } + bool operator!=(const new_iterator&) const { return false; } + bool operator<(const new_iterator&) const { return false; } + int* m_x; +}; +new_iterator operator+(std::ptrdiff_t, new_iterator x) { return x; } + +struct old_iterator + : public boost::iterator +{ + int& operator*() const { return *m_x; } + old_iterator& operator++() { return *this; } + old_iterator operator++(int) { return *this; } + old_iterator& operator--() { return *this; } + old_iterator operator--(int) { return *this; } + old_iterator& operator+=(std::ptrdiff_t) { return *this; } + old_iterator operator+(std::ptrdiff_t) { return *this; } + old_iterator& operator-=(std::ptrdiff_t) { return *this; } + old_iterator operator-(std::ptrdiff_t) const { return *this; } + std::ptrdiff_t operator-(const old_iterator&) const { return 0; } + bool operator==(const old_iterator&) const { return false; } + bool operator!=(const old_iterator&) const { return false; } + bool operator<(const old_iterator&) const { return false; } + int* m_x; +}; +old_iterator operator+(std::ptrdiff_t, old_iterator x) { return x; } + +int +main() +{ +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + boost::function_requires< + boost_concepts::MutableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessIteratorConcept >(); + + boost::function_requires< + boost_concepts::ConstantLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessIteratorConcept >(); +#endif + + boost::function_requires< + boost_concepts::MutableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessIteratorConcept >(); + + boost::function_requires< + boost_concepts::MutableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessIteratorConcept >(); + return 0; +} diff --git a/iterator_categories.htm b/iterator_categories.htm new file mode 100644 index 0000000..83c29e5 --- /dev/null +++ b/iterator_categories.htm @@ -0,0 +1,160 @@ + + + + Boost Iterator Traits + + + +C++ Boost +
+ +

Boost Iterator Category Traits

+Header boost/iterator_categories.hpp + +

+The boost::traversal_category and +boost::return_category traits classes provides access to the +category tags for iterators that model the Boost Iterator Concepts, which are a +replacement for the iterator requirements in the C++ standard. The +other associated types of the Boost iterator concepts are accessed +through the std::iterator_traits class. + +

    +
  • traversal_category<Iter>::type   Can the iterator go forward, backward, etc.? +
  • return_category<Iter>::type   Is the iterator read or write only? + Is the dereferenced type an lvalue? +
+ +

+An important feature of the boost::traversal_category and +boost::return_category classes is that they are backwards +compatible, i.e., they automatically work for iterators for which +there are valid definitions of std::iterator_traits. The old +iterator_category is mapped to the appropriate traversal and +return categories. + +

+When creating a new iterator type that is meant to work with +boost::traversal_category and +boost::return_category, you can either create a +specialization of these classes for your iterator type, or you can +provide all the necessary associated types as nested typedefs. In +this case, your iterator class will need to inherit from +new_iterator_base to let the category traits know +that it will be able to find typedefs for traversal_category +and return_category in you iterator class. + + +Each of the new iterator requirements will need a category tag. + +

+namespace boost {
+
+  // Return Type Categories
+  struct readable_iterator_tag { };
+  struct writable_iterator_tag { };
+  struct swappable_iterator_tag { };
+  struct mutable_lvalue_iterator_tag : virtual public writable_iterator_tag,
+    virtual public readable_iterator_tag { };
+  struct constant_lvalue_iterator_tag : public readable_iterator_tag { };
+
+  // Traversal Categories
+  struct forward_traversal_tag { };
+  struct bidirectional_traversal_tag : public forward_traversal_tag { };
+  struct random_access_traversal_tag : public bidirectional_traversal_tag { };
+
+}
+
+ +

+The following is pseudo-code for the iterator category traits classes. + +

+namespace boost {
+
+  // Inherit from iterator_base if your iterator defines its own
+  // return_category and traversal_category. Otherwise, the "old style"
+  // iterator category will be mapped to the return_category and
+  // traversal_category.
+  struct new_iterator_base { };
+
+  template <typename Iterator>
+  struct return_category
+  {
+    // Pseudo-code
+    if (Iterator inherits from new_iterator_base) {
+      typedef typename Iterator::return_category type;
+    } else {
+      typedef std::iterator_traits<Iterator> OldTraits;
+      typedef typename OldTraits::iterator_category Cat;
+      if (Cat inherits from std::forward_iterator_tag)
+	if (is-const(T))
+	  typedef boost::constant_lvalue_iterator_tag type;
+	else
+	  typedef boost::mutable_lvalue_iterator_tag type;
+      else if (Cat inherits from std::input_iterator_tag)
+	typedef boost::readable_iterator_tag type;
+      else if (Cat inherits from std::output_iterator_tag)
+	typedef boost::writable_iterator_tag type;
+    }
+  };
+
+  template <typename T>
+  struct return_category<T*>
+  {
+    // Pseudo-code
+    if (is-const(T))
+      typedef boost::constant_lvalue_iterator_tag type;
+    else
+      typedef boost::mutable_lvalue_iterator_tag type;
+  };
+
+  template <typename Iterator>
+  struct traversal_category
+  {
+    // Pseudo-code
+    if (Iterator inherits from new_iterator_base) {
+      typedef typename Iterator::traversal_category type;
+    } else {
+      typedef std::iterator_traits<Iterator> OldTraits;
+      typedef typename OldTraits::iterator_category Cat;
+
+      if (Cat inherits from std::random_access_iterator_tag)
+	typedef boost::random_access_traversal_tag type;
+      else if (Cat inherits from std::bidirectional_iterator_tag)
+	typedef boost::bidirectional_traversal_tag type;
+      else if (Cat inherits from std::forward_iterator_tag)
+	typedef boost::forward_traversal_tag type;
+    }
+  };
+
+  template <typename T>
+  struct traversal_category<T*>
+  {
+    typedef boost::random_access_traversal_tag type;
+  };
+
+}
+
+ +
+
jeremy siek
+ + +Last modified: Mon Mar 19 12:59:30 EST 2001 + + + diff --git a/iterator_concepts.fig b/iterator_concepts.fig new file mode 100644 index 0000000..198205e --- /dev/null +++ b/iterator_concepts.fig @@ -0,0 +1,37 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +6 150 2325 4275 4350 +2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1725 4050 1725 3450 +2 1 0 1 0 7 100 0 -1 4.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 1725 3150 1725 2550 +4 0 0 100 0 19 18 0.0000 4 210 3180 375 2550 ForwardTraversalIterator\001 +4 0 0 100 0 19 18 0.0000 4 210 3765 225 3450 BidirectionalTraversalIterator\001 +4 0 0 100 0 19 18 0.0000 4 210 4125 150 4350 RandomAccessTraversalIterator\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 4800 3600 4800 2400 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6900 3000 5400 2400 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6900 3000 7500 2400 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 1 1 1.00 60.00 120.00 + 6900 3000 9075 2475 +4 0 0 100 0 19 18 0.0000 4 210 2040 6600 2400 WritableIterator\001 +4 0 0 100 0 19 18 0.0000 4 210 2145 3900 2400 ReadableIterator\001 +4 0 0 50 0 19 18 0.0000 4 210 2835 5700 3300 MutableLvalueIterator\001 +4 0 0 50 0 19 18 0.0000 4 270 2355 9075 2400 SwappableIterator\001 +4 0 0 50 0 19 18 0.0000 4 210 2970 3825 3900 ConstantLvalueIterator\001 diff --git a/iterator_concepts.gif b/iterator_concepts.gif new file mode 100644 index 0000000..bac35c7 Binary files /dev/null and b/iterator_concepts.gif differ diff --git a/iterator_concepts.htm b/iterator_concepts.htm new file mode 100644 index 0000000..f2f8dcd --- /dev/null +++ b/iterator_concepts.htm @@ -0,0 +1,663 @@ + + + + +Iterator Concepts + +C++ Boost + +
+ + +

Iterator Concepts

+ +

The standard iterator categories and requirements are flawed because +they use a single hierarchy of requirements to address two orthogonal +issues: iterator traversal and dereference return +type. The current iterator requirement hierarchy is mainly +geared towards iterator traversal (hence the category names), while +requirements that address dereference return type sneak in at various +places. + +

+The iterator requirements should be separated into two hierarchies. +One set of concepts handles the return type semantics: +

+ +The other set of concepts handles iterator traversal: + + + +The current Input Iterator and Output Iterator requirements will +continue to be used as is. Note that Input Iterator implies Readable +Iterator and Output Iterator implies Writable Iterator. + +

+Note: we considered defining a Single-Pass Iterator, which could be +combined with Readable or Writable Iterator to replace the Input and +Output Iterator requirements. We rejected this idea because there are +some differences between Input and Output Iterators that make it hard +to merge them: for example Input Iterator requires Equality Comparable +while Output Iterator does not. + + +

+
+ + + +
Figure 1: +The iterator concepts and refinement relationships. +
+
+

+ + +

Relationship with the standard iterator concepts

+ +

+std::Input Iterator implies boost::ReadableIterator. + +

+std::Output Iterator implies boost::Writable Iterator. + +

+std::Forward Iterator refines boost::Forward Iterator and +boost::Constant Lvalue Iterator or boost::Mutable Lvalue Iterator. + +

+std::Bidirectional Iterator refines boost::Bidirectional Iterator and +boost::Constant Lvalue Iterator or boost::Mutable Lvalue Iterator. + +

+std::Random Access Iterator refines boost::Random Access Iterator and +boost::Constant Lvalue Iterator or boost::Mutable Lvalue Iterator. + + +

Notation

+ + + + + + + + + + + + + + + + + +
XThe iterator type.
TThe value type of X, i.e., std::iterator_traits<X>::value_type.
x, yAn object of type X.
tAn object of type T.
+ +

+ +


+ + +

+Readable Iterator +

+ +A Readable Iterator is an iterator that dereferences to produce an +rvalue that is convertible to the value_type of the +iterator. + +

Associated Types

+ + + + + + + + + + + + + + + + + + + + + +
Value typestd::iterator_traits<X>::value_typeThe type of the objects pointed to by the iterator.
Reference typestd::iterator_traits<X>::reference + The return type of dereferencing the iterator. This + type must be convertible to T. +
Return Categorystd::return_category<X>::type + A type convertible to std::readable_iterator_tag +
+ +

Refinement of

+ +Copy Constructible + +

Valid expressions

+ + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Dereference*x std::iterator_traits<X>::reference
Member accessx->mT is a type with a member named m. +If m is a data member, the type of m. +If m is a member function, the return type of m. +
+ +

+ +


+ + +

+Writable Iterator +

+ +A Writable Iterator is an iterator that can be used to store a value +using the dereference-assignment expression. + +

Definitions

+ +If x is an Writable Iterator of type X, then the +expression *x = a; stores the value a into +x. Note that operator=, like other C++ functions, +may be overloaded; it may, in fact, even be a template function. In +general, then, a may be any of several different types. A +type A belongs to the set of value types of X +if, for an object a of type A, *x = a; is +well-defined and does not require performing any non-trivial +conversions on a. + +

Associated Types

+ + + + + + + + + +
Return Categorystd::return_category<X>::type + A type convertible to std::writable_iterator_tag +
+ + + +

Refinement of

+ +Copy Constructible + +

Valid expressions

+ + + + + + + + + + +
NameExpressionReturn type
Dereference assignment*x = aunspecified
+ +

+ + +


+ + +

+Swappable Iterator +

+ +A Swappable Iterator is an iterator whose dereferenced values can be +swapped. + +

+Note: the requirements for Swappable Iterator are dependent on the +issues surrounding std::swap() being resolved. Here we assume +that the issue will be resolved by allowing the overload of +std::swap() for user-defined types. + +

+Note: Readable Iterator and Writable Iterator combined implies +Swappable Iterator because of the fully templated +std::swap(). However, Swappable Iterator does not imply +Readable Iterator nor Writable Iterator. + +

Associated Types

+ + + + + + + + + +
Return Categorystd::return_category<X>::type + A type convertible to std::swappable_iterator_tag +
+ + +

Valid expressions

+ +Of the two valid expressions listed below, only one OR the +other is required. If std::iter_swap() is overloaded for +X then std::swap() is not required. If +std::iter_swap() is not overloaded for X then the +default (fully templated) version is used, which will call +std::swap() (this means changing the current requirements for +std::iter_swap()). + +

+ + + + + + + + + + + + + + + + + +
NameExpressionReturn type
Iterator Swapstd::iter_swap(x, y)void
Dereference and Swapstd::swap(*x, *y)void
+ +

+ + +


+ + +

+Constant Lvalue Iterator +

+ +A Constant Lvalue Iterator is an iterator that dereferences to produce a +const reference to the pointed-to object, i.e., the associated +reference type is const T&. Changing the value +of or destroying an iterator that models Constant Lvalue Iterator does +not invalidate pointers and references previously obtained from that +iterator. + + +

Refinement of

+ +Readable Iterator + +

Associated Types

+ + + + + + + + + + + + + + + + + +
Reference typestd::iterator_traits<X>::reference + The return type of dereferencing the iterator, which must be + const T&. +
Return Categorystd::return_category<X>::type + A type convertible to std::constant_lvalue_iterator_tag +
+ + + +

+ +


+ + +

+Mutable Lvalue Iterator +

+ +A Mutable Lvalue Iterator is an iterator that dereferences to produce a +reference to the pointed-to object. The associated reference +type is T&. Changing the value of or destroying an +iterator that models Mutable Lvalue Iterator does not invalidate +pointers and references previously obtained from that iterator. + +

Refinement of

+ +Readable Iterator, +Writable Iterator, +and Swappable Iterator. + + + +

Associated Types

+ + + + + + + + + + + + + + + + + +
Reference typestd::iterator_traits<X>::referenceThe return type of dereferencing the iterator, which must be + T&.
Return Categorystd::return_category<X>::type + A type convertible to std::mutable_lvalue_iterator_tag +
+ + + +

+


+ + +

+Forward Traversal Iterator +

+ +The Forward Iterator is an iterator that can be incremented. Also, it +is permissible to make multiple passes through the iterator's range. + +

Refinement of

+ +Copy Constructible, +Assignable, +Default Constructible, and +Equality Comparable + + +

Associated types

+ + + + + + + + + + + + + + +
Difference Typestd::iterator_traits<X>::difference_type + A signed integral type used for representing distances + between iterators that point into the same range. +
Traversal Categorystd::traversal_category<X>::type + A type convertible to std::forward_traversal_tag +
+ +

Valid expressions

+ + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Preincrement++i X&
Postincrementi++ convertible to const X&
+ +

+


+ + +

+Bidirectional Traversal Iterator +

+ +An iterator that can be incremented and decremented. + +

Refinement of

+ +Forward Traversal Iterator + +

Associated types

+ + + + + + + +
Traversal Categorystd::traversal_category<X>::type + A type convertible to std::bidirectional_traversal_tag +
+ +

Valid expressions

+ + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Predecrement--i X&
Postdecrementi-- convertible to const X&
+ +

+


+ + +

+Random Access Traversal Iterator +

+ +An iterator that provides constant-time methods for moving forward and +backward in arbitrary-sized steps. + +

Refinement of

+ +Bidirectional Traversal Iterator and +Less Than Comparable where < is a total ordering + +

Associated types

+ + + + + + + +
Traversal Categorystd::traversal_category<X>::type + A type convertible to std::random_access_traversal_tag +
+ +

Valid expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameExpressionType requirementsReturn type
Iterator additioni += n X&
Iterator additioni + n or n + i X
Iterator subtractioni -= n X&
Iterator subtractioni - n X
Differencei - j std::iterator_traits<X>::difference_type
Element operatori[n]X must also be a model of + Readable Iterator. std::iterator_traits<X>::reference
Element assignmenti[n] = tX must also be a model of + Writable Iterator.unspecified
+ +

+ +


+ + +
Copyright © 2000 +Jeremy Siek, Univ.of Notre Dame (jsiek@lsc.nd.edu) +
+ + +