diff --git a/doc/iterator-categories.html b/doc/iterator-categories.html new file mode 100644 index 0000000..2622197 --- /dev/null +++ b/doc/iterator-categories.html @@ -0,0 +1,740 @@ + +
+
Output Iterator | +*i = a |
Input Iterator | +*i is convertible to T |
Forward Iterator | +*i is T& (or const T& once issue + 200 is resolved) |
Random Access Iterator | +i[n] is convertible to T (which is odd because the + operational semantics say i[n] is equivalent to *(i + n) + which would have a return type of T&) |
Because of the mixing of iterator traversal and dereference return type, many +useful iterators can not be appropriately categorized. For example, +vector<bool>::iterator is almost a random access iterator, but +the return type is not bool& (see issue +96 and Herb Sutter's paper J16/99-0008 = WG21 N1185). Therefore, the +iterators only meet the requirements of input iterator and output iterator. This +is so nonintuitive that at least one implementation erroneously assigns +random_access_iterator_tag as its iterator_category. Also, +vector<bool> is not the only example of useful iterators that do +not return true references: there is the often cited example of disk-based +collections. +
Another example is a counting iterator, an iterator the returns a sequence of +integers when incremented and dereferenced (see boost::counting_iterator). +There are two ways to implement this iterator, 1) make the reference +type be a true reference (a reference to an integer data member of the counting +iterator) or 2) make the reference type be the same as the +value_type. Option 1) runs into the problems discussed in Issue +198, the reference will not be valid after the iterator is destroyed. Option +2) is therefore a better choice, but then we have a counting iterator that +cannot be a random access iterator. +
Yet another example is a transform iterator, an iterator adaptor that applies +a unary function object to the dereference value of the wrapped iterator (see boost::transform_iterator). +For unary functions such as std::times the return type of +operator* clearly needs to be the result_type of the function +object, which is typically not a reference. However, with the current iterator +requirements, if you wrap int* with a transform iterator, you do not +get a random access iterator as expected, but an input iterator. +
A fourth example is found in the vertex and edge iterators of the Boost Graph +Library. These iterators return vertex and edge descriptors, which are +lightweight handles created on-the-fly. They must be returned by-value. As a +result, their current standard iterator category is +std::input_iterator_tag, which means that, strictly speaking, you could +not use these iterators with algorithms like std::min_element(). As a +temporary solution, we introduced the concept Multi-Pass +Input Iterator to describe the vertex and edge descriptors, but as the +design notes for concept suggest, a better solution is needed. +
In short, there are many useful iterators that do not fit into the current +standard iterator categories. As a result, the following bad things happen: +
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 several differences +between Input and Output Iterators that make it hard to merge them: Input +Iterator requires Equality Comparable while Output Iterator does not and Input +Iterator requires Assignable while Output Iterator does not. +
namespace std { + + // 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 { }; + +} +And there will need to be a way to access these category tags using a +traits mechanism. Adding new typedefs to std::iterator_traits is not an +acceptable solution because that would break every existing iterator. Instead, +we propose two new traits classes. It is important that these traits classes are +backward compatible, that is, they should work with any iterator for +which there is a valid definition of std::iterator_traits. This can be +accomplished by making the default behavior of the traits classes map the +iterator_category of the iterator to the appropriate return or +traversal category. For new iterators, either specializations of these traits +classes can be defined, or the iterator can provide nested typedefs, and inherit +from new_iterator_base (which is just a signal to the traits class that +it is a new iterator). As with std::iterator_traits, specializations +for T* are provided.
namespace std { + + 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; + }; + +} ++
+
Algorithm | +Requirement Change |
---|---|
find_end | +Forward Iterator -> Forward Traversal Iterator and + Readable Iterator |
find_first_of | |
adjacent_find | |
search | |
search_n | |
rotate_copy | |
lower_bound | |
upper_bound | |
equal_range | |
binary_search | |
min_element | |
max_element | |
iter_swap | +Forward Iterator -> Swappable Iterator |
fill | +Forward Iterator -> Forward Traversal Iterator and + Writable Iterator |
generate | |
swap_ranges | +Forward Iterator -> Forward Traversal Iterator and + Swappable Iterator |
rotate | |
replace | +Forward Iterator -> Forward Traversal Iterator + and Readable Iterator and Writable Iterator |
+
replace_if | |
remove | |
remove_if | |
unique | |
reverse | +Bidirectional Iterator -> Bidirectional Traversal + Iterator and Swappable Iterator |
partition | |
copy_backwards | +Bidirectional Iterator -> Bidirectional Traversal Iterator and + Readable Iterator Bidirectional Iterator -> Bidirectional + Traversal Iterator and Writable Iterator |
next_permutation | +Bidirectional Iterator -> Bidirectional Traversal + Iterator and Swappable Iterator and Readable Iterator |
+
prev_permutation | |
stable_partition | +Bidirectional Iterator -> Bidirectional Traversal + Iterator and Readable Iterator and Writable Iterator |
+
inplace_merge | |
reverse_copy | +Bidirectional Iterator -> Bidirectional Traversal Iterator and + Readable Iterator |
random_shuffle | +Random Access Iterator -> Random Access Traversal + Iterator and Swappable Iterator |
sort | |
stable_sort | |
partial_sort | |
nth_element | |
push_heap | |
pop_heap | |
make_heap | |
sort_heap |
X | +The iterator type. |
T | +The value type of X, i.e., + std::iterator_traits<X>::value_type. |
x, y | +An object of type X. |
t | +An object of type T. |
+
Value type | +std::iterator_traits<X>::value_type | +The type of the objects pointed to by the iterator. |
Reference type | +std::iterator_traits<X>::reference | +The return type of dereferencing the iterator. This type must be + convertible to T. |
Return Category | +std::return_category<X>::type | +A type convertible to std::readable_iterator_tag + |
Name | +Expression | +Type requirements | +Return type |
---|---|---|---|
Dereference | +*x | ++ | std::iterator_traits<X>::reference |
Member access | +x->m | +T 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. |
+
Return Category | +std::return_category<X>::type | +A type convertible to std::writable_iterator_tag + |
Name | +Expression | +Return type |
---|---|---|
Dereference assignment | +*x = a | +unspecified |
+
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. +
Return Category | +std::return_category<X>::type | +A type convertible to std::swappable_iterator_tag + |
+
Name | +Expression | +Return type |
---|---|---|
Iterator Swap | +std::iter_swap(x, y) | +void |
Dereference and Swap | +std::swap(*x, *y) | +void |
+
Reference type | +std::iterator_traits<X>::reference | +The return type of dereferencing the iterator, which must be const + T&. |
Return Category | +std::return_category<X>::type | +A type convertible to std::constant_lvalue_iterator_tag + |
+
Reference type | +std::iterator_traits<X>::reference | +The return type of dereferencing the iterator, which must be + T&. |
Return Category | +std::return_category<X>::type | +A type convertible to std::mutable_lvalue_iterator_tag + |
+
Difference Type | +std::iterator_traits<X>::difference_type | +A signed integral type used for representing distances between + iterators that point into the same range. |
Traversal Category | +std::traversal_category<X>::type | +A type convertible to std::forward_traversal_tag + |
Name | +Expression | +Type requirements | +Return type |
---|---|---|---|
Preincrement | +++i | ++ | X& |
Postincrement | +i++ | ++ | convertible to const X& |
+
Traversal Category | +std::traversal_category<X>::type | +A type convertible to std::bidirectional_traversal_tag + |
Name | +Expression | +Type requirements | +Return type |
---|---|---|---|
Predecrement | +--i | ++ | X& |
Postdecrement | +i-- | ++ | convertible to const X& |
+
Traversal Category | +std::traversal_category<X>::type | +A type convertible to std::random_access_traversal_tag + |
Name | +Expression | +Type requirements | +Return type |
---|---|---|---|
Iterator addition | +i += n | ++ | X& |
Iterator addition | +i + n or n + i | ++ | X |
Iterator subtraction | +i -= n | ++ | X& |
Iterator subtraction | +i - n | ++ | X |
Difference | +i - j | ++ | std::iterator_traits<X>::difference_type |
Element operator | +i[n] | +X must also be a model of Readable + Iterator. | +std::iterator_traits<X>::reference |
Element assignment | +i[n] = t | +X must also be a model of Writable + Iterator. | +unspecified |
+