diff --git a/doc/iterator-categories.html b/doc/iterator-categories.html deleted file mode 100644 index eb76523..0000000 --- a/doc/iterator-categories.html +++ /dev/null @@ -1,822 +0,0 @@ - -
-
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: -
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 -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.
- -The new iterator categories will require new tag classes.
- -namespace std { - - // Returns Category Tags - 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 Category Tags - struct input_traversal_tag { }; - struct output_traversal_tag { }; - struct forward_traversal_tag { }; - struct bidirectional_traversal_tag : public forward_traversal_tag { }; - struct random_access_traversal_tag : public bidirectional_traversal_tag { }; - -} -- -
Access to the return and traversal tags will be through the -following two traits classes, which have a member typedef named -type that provides the tag type. We explain the -definitions of these classes later.
- -- template <typename Iterator> - struct return_category; // contains: typedef ... type; - - template <typename Iterator> - struct traversal_category; // contains: typedef ... type; -- -
We want it to be convenient for programmers to create iterators -that satisfy both the old and new iterator requirements. Therefore -the following class is provided as a way to create tags for use as the -old iterator_category typedef within -iterator_traits. - -
namespace std { - template <class ReturnTag, class TraversalTag> - struct iterator_tag : cvt_iterator_category<ReturnTag, TraversalTag>::type - { - typedef ReturnTag returns; - typedef TraversalTag traversal; - }; -- -
The cvt_iterator_category template computes the -appropriate old iterator category based on the return and traversal -category.
- -namespace std { - template <class RC, class TC> - struct cvt_iterator_category - { - // Pseudo-code, <= means inherits or same type - if (RC <= constant_lvalue_iterator_tag || RC <= mutable_lvalue_iterator_tag) { - if (TC <= random_access_traversal_tag) - typedef random_access_iterator_tag type; - else if (TC <= bidirectional_traversal_tag) - typedef bidirectional_iterator_tag type; - else if (TC <= forward_traversal_tag) - typedef forward_iterator_tag type; - else - error; - } else if (RC <= readable_iterator_tag && RC <= input_traversal_tag) - typedef input_iterator_tag type; - else if (RC <= writable_iterator_tag && output_traversal_tag) - typedef output_iterator_tag type; - else - error; - }; -} -- -
The following is an example of a new iterator class using the -iterator_tag class to create its iterator_category -member typedef.
- --struct my_iterator { - typedef std::iterator_tag<std::readable_iterator_tag, - std::random_access_traversal_tag> iterator_category; - ... -}; -- -We also want old iterators to work with new algorithms, that is, -algorithms that use the new iterator categories. We facilitate this by -defining the return_category and traversal_category -in such a way as they can be used with both old and new iterators. -For old iterators, the appropriate return and traversal categories are -computed based on the old iterator category. For new iterators, the -return and traversal tags are extracted from within the -iterator_category tag. - - -
- template <typename Iterator> - class return_category - { - // Pseudo-code - typedef iterator_traits<Iterator>::iterator_category tag; - typedef iterator_traits<Iterator>::value_type T; - public: - if (exists(tag::returns)) // must be a new iterator - typedef tag::returns type; - else if (tag <= forward_iterator_tag) { - if (is-const(T)) - typedef constant_lvalue_iterator_tag type; - else - typedef mutable_lvalue_iterator_tag type; - } else if (tag <= input_iterator_tag) - typedef readable_iterator_tag type; - else if (tag <= output_iterator_tag) - typedef writable_iterator_tag type; - else - error; - }; - - 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> - class traversal_category - { - typedef iterator_traits<Iterator>::iterator_category tag; - public: - // Pseudo-code - if (exists(tag::traversal)) // must be a new iterator - typedef tag::traversal type; - else if (tag <= random_access_iterator_tag) - typedef random_access_traversal_tag type; - else if (tag <= bidirectional_iterator_tag) - typedef bidirectional_traversal_tag type; - else if (tag <= is_forward_iterator_tag) - typedef forward_traversal_tag type; - else if (tag <= input_iterator_tag) - typedef input_traversal_tag type; - else if (tag <= out_iterator_tag) - typedef output_traversal_tag type; - else - error; - }; - - template <typename T> - struct traversal_category<T*> - { - typedef random_access_traversal_tag type; - }; -- -
Many of the standard algorithms place more requirements than -necessary on their iterator parameters due to the coarseness of the -current iterator categories. By using the new iterator categories a -better fit can be achieved, thereby increasing the reusability of the -algorithms. These changes will not affect user-code, though they will -require changes by standard implementers: dispatching should be based -on the new categories, and in places return values may need to be -handled more carefully. In particular, uses of std::swap() -will need to be replaced with std::iter_swap(), and -std::iter_swap() will need to call std::swap().
- --
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 |
-