diff --git a/doc/BidirectionalTraversal.html b/doc/BidirectionalTraversal.html new file mode 100644 index 0000000..0daa77e --- /dev/null +++ b/doc/BidirectionalTraversal.html @@ -0,0 +1,71 @@ + + + +
+ + +A class or built-in type X models the Bidirectional Traversal +concept if, in addition to X meeting the requirements of Forward +Traversal Iterator, the following expressions are valid and respect +the stated semantics.
+Bidirectional Traversal Iterator Requirements (in addition to Forward Traversal +Iterator) | +||
---|---|---|
Expression | +Return Type | +Assertion/Semantics / +Pre-/Post-condition | +
--r | +X& | +pre: there exists +s such that r +== ++s. post: +s is +dereferenceable. +--(++r) == r. +--r == --s +implies r == +s. &r == &--r. | +
r-- | +convertible to const X& | ++{ + X tmp = r; + --r; + return tmp; +} ++ |
+
iterator_traversal<X>::type | +Convertible to +bidirectional_traversal_tag | ++ |
A class or built-in type X models the Forward Traversal +concept if, in addition to X meeting the requirements of Default +Constructible and Single Pass Iterator, the following expressions are +valid and respect the stated semantics.
+Forward Traversal Iterator Requirements (in addition to Default Constructible and Single Pass Iterator) | +||
---|---|---|
Expression | +Return Type | +Assertion/Note | +
X u; | +X& | +note: u may have a +singular value. | +
++r | +X& | +r == s and r is +dereferenceable implies +++r == ++s. | +
iterator_traits<X>::difference_type | +A signed integral type representing +the distance between iterators | ++ |
iterator_traversal<X>::type | +Convertible to +forward_traversal_tag | ++ |
A class or built-in type X models the Incrementable Iterator +concept if, in addition to X being Assignable and Copy +Constructible, the following expressions are valid and respect the +stated semantics.
+Incrementable Iterator Requirements (in addition to Assignable, Copy Constructible) | +||
---|---|---|
Expression | +Return Type | +Assertion/Semantics | +
++r | +X& | +&r == &++r | +
r++ | +X | ++{ + X tmp = r; + ++r; + return tmp; +} ++ |
+
iterator_traversal<X>::type | +Convertible to +incrementable_traversal_tag | ++ |
The Lvalue Iterator concept adds the requirement that the return +type of operator* type be a reference to the value type of the +iterator.
+Lvalue Iterator Requirements | +||
---|---|---|
Expression | +Return Type | +Note/Assertion | +
*a | +T& | +T is cv +iterator_traits<X>::value_type +where cv is an optional +cv-qualification. +pre: a is +dereferenceable. If a +== b then *a is +equivalent to *b. | +
A class or built-in type X models the Random Access Traversal +concept if the following expressions are valid and respect the stated +semantics. In the table below, Distance is +iterator_traits<X>::difference_type and n represents a +constant object of type Distance.
+Random Access Traversal Iterator Requirements (in addition to Bidirectional Traversal) | +|||
---|---|---|---|
Expression | +Return Type | +Operational Semantics | +Assertion/ +Precondition | +
r += n | +X& | ++{ + Distance m = n; + if (m >= 0) + while (m--) + ++r; + else + while (m++) + --r; + return r; +} ++ |
++ |
a + n, n + a | +X | +{ X tmp = a; return tmp ++= n; } | ++ |
r -= n | +X& | +return r += -n | ++ |
a - n | +X | +{ X tmp = a; return tmp +-= n; } | ++ |
b - a | +Distance | +a < b ? distance(a,b) +: -distance(b,a) | +pre: there exists a +value n of +Distance such that +a + n == b. b +== a + (b - a). | +
a[n] | +convertible to T | +*(a + n) | +pre: a is a Readable +Iterator | +
a[n] = v | +convertible to T | +*(a + n) = v | +pre: a is a Writable +iterator | +
a < b | +convertible to bool | +b - a > 0 | +< is a total +ordering relation | +
a > b | +convertible to bool | +b < a | +> is a total +ordering relation | +
a >= b | +convertible to bool | +!(a < b) | ++ |
a <= b | +convertible to bool | +!(a > b) | ++ |
iterator_traversal<X>::type | +Convertible to +random_access_traversal_tag | ++ | + |
A class or built-in type X models the Readable Iterator concept +for value type T if, in addition to X being Assignable and +Copy Constructible, the following expressions are valid and respect +the stated semantics. U is the type of any specified member of +type T.
+Readable Iterator Requirements (in addition to Assignable and Copy Constructible) | +||
---|---|---|
Expression | +Return Type | +Note/Precondition | +
iterator_traits<X>::value_type | +T | +Any non-reference, +non-cv-qualified type | +
*a | +Convertible to T | +
|
+
a->m | +U& | +pre: pre: (*a).m is well-defined. Equivalent to (*a).m. | +
A class or built-in type X models the Single Pass Iterator +concept if the following expressions are valid and respect the stated +semantics.
+Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality +Comparable) | +||
---|---|---|
Expression | +Return Type | +Assertion/Semantics / +Pre-/Post-condition | +
++r | +X& | +pre: r is +dereferenceable; post: +r is dereferenceable or +r is past-the-end | +
a == b | +convertible to bool | +== is an equivalence +relation over its domain | +
a != b | +convertible to bool | +!(a == b) | +
iterator_traversal<X>::type | +Convertible to +single_pass_traversal_tag | ++ |
A class or built-in type X models the Swappable Iterator concept +if, in addition to X being Copy Constructible, the following +expressions are valid and respect the stated semantics.
+Swappable Iterator Requirements (in addition to Copy Constructible) | +||
---|---|---|
Expression | +Return Type | +Postcondition | +
iter_swap(a, b) | +void | +the pointed to values are +exchanged | +
A class or built-in type X models the Writable Iterator concept +if, in addition to X being Copy Constructible, the following +expressions are valid and respect the stated semantics. Writable +Iterators have an associated set of value types.
+Writable Iterator Requirements (in addition to Copy Constructible) | +||
---|---|---|
Expression | +Return Type | +Precondition | +
*a = o | ++ | pre: The type of o +is in the set of +value types of X | +
+template <class Predicate, class Iterator> +class filter_iterator +{ + public: + typedef iterator_traits<Iterator>::value_type value_type; + typedef iterator_traits<Iterator>::reference reference; + typedef iterator_traits<Iterator>::pointer pointer; + typedef iterator_traits<Iterator>::difference_type difference_type; + typedef /* see below */ iterator_category; + + filter_iterator(); + filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); + filter_iterator(Iterator x, Iterator end = Iterator()); + template<class OtherIterator> + filter_iterator( + filter_iterator<Predicate, OtherIterator> const& t + , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition + ); + Predicate predicate() const; + Iterator end() const; + Iterator base() const; + reference operator*() const; + filter_iterator& operator++(); +private: + Predicate m_pred; // exposition + Iterator m_iter; // exposition + Iterator m_end; // exposition +}; ++
The iterator_category member is a type convertible to the tags +corresponding to each standard concept modeled by filter_iterator, +as described in the models section.
+The Predicate argument must be Assignable, Copy Constructible, and +the expression p(x) must be valid where p is an object of type +Predicate, x is an object of type +iterator_traits<Iterator>::value_type, and where the type of +p(x) must be convertible to bool.
+The Iterator argument shall meet the requirements of Readable +Iterator and Single Pass Iterator or it shall meet the requirements of +Input Iterator.
+The concepts that filter_iterator models are dependent on which +concepts the Iterator argument models, as specified in the +following tables.
+If Iterator models | +then filter_iterator models | +
---|---|
Single Pass Iterator | +Single Pass Iterator | +
Forward Traversal Iterator | +Forward Traversal Iterator | +
If Iterator models | +then filter_iterator models | +
---|---|
Readable Iterator | +Readable Iterator | +
Writable Iterator | +Writable Iterator | +
Lvalue Iterator | +Lvalue Iterator | +
If Iterator models | +then filter_iterator models | +
---|---|
Readable Iterator, Single Pass Iterator | +Input Iterator | +
Readable Lvalue Iterator, Forward Traversal Iterator | +Forward Iterator | +
Writable Lvalue Iterator, Forward Traversal Iterator | +Mutable Forward Iterator | +
In addition to those operations required by the concepts that +filter_iterator models, filter_iterator provides the following +operations.
+filter_iterator();
+Requires: | Predicate and Iterator must be Default Constructible. | +
---|---|
Returns: | a filter_iterator whose``m_pred``, m_iter, and m_end +members are a default constructed. | +
filter_iterator(Predicate f, Iterator x, Iterator end = Iterator());
+Returns: | A filter_iterator where m_iter is either +the first position in the range [x,end) such that f(*m_iter) == true +or else``m_iter == end``. The member m_pred is constructed from +f and m_end from end. | +
---|
filter_iterator(Iterator x, Iterator end = Iterator());
+Requires: | Predicate must be Default Constructible. | +
---|---|
Returns: | A filter_iterator where m_iter is either +the first position in the range [x,end) such that m_pred(*m_iter) == true +or else``m_iter == end``. The member m_pred is default constructed. | +
+template <class OtherIterator> +filter_iterator( + filter_iterator<Predicate, OtherIterator> const& t + , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition + );`` ++
Requires: | OtherIterator is implicitly convertible to Iterator. | +
---|---|
Returns: | A filter iterator whose members are copied from t. | +
Predicate predicate() const;
+Returns: | m_pred | +
---|
Iterator end() const;
+Returns: | m_end | +
---|
Iterator base() const;
+Returns: | m_iterator | +
---|
reference operator*() const;
+Returns: | *m_iter | +
---|
filter_iterator& operator++();
+Effects: | Increments m_iter and then continues to +increment m_iter until either m_iter == m_end +or m_pred(*m_iter) == true. | +
---|---|
Returns: | *this | +
+template < + class Iterator + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class indirect_iterator +{ + public: + typedef /* see below */ value_type; + typedef /* see below */ reference; + typedef /* see below */ pointer; + typedef /* see below */ difference_type; + typedef /* see below */ iterator_category; + + indirect_iterator(); + indirect_iterator(Iterator x); + + template < + class Iterator2, class Value2, class Category2 + , class Reference2, class Difference2 + > + indirect_iterator( + indirect_iterator< + Iterator2, Value2, Category2, Reference2, Difference2 + > const& y + , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition + ); +}; ++
The member types of indirect_iterator are defined according to the +following pseudo-code. We use the abbreviation +V=iterator_traits<Iterator>::value_type and v is an object of +type V.:
++if (Value is use_default) then + typedef iterator_traits<V>::value_type value_type; +else + typedef remove_const<Value>::type value_type; + +if (Reference is use_default) then + typedef iterator_traits<V>::reference reference; +else + typedef Reference reference; + +typedef Value* pointer; + +if (Difference is use_default) + typedef iterator_traits<Iterator>::difference_type difference_type; +else + typedef Difference difference_type; ++
The member indirect_iterator::iterator_category is a type that +satisfies the requirements of the concepts modeled by the indirect +iterator as specified in the models section.
+The Iterator argument shall meet the requirements of Readable +Iterator. The CategoryOrTraversal argument shall be one of the +standard iterator tags or use_default. If CategoryOrTraversal +is an iterator tag, the template parameter Iterator argument shall +meet the traversal requirements corresponding to the iterator tag.
+The expression *v, where v is an object of type +iterator_traits<Iterator>::value_type, must be a valid expression +and must be convertible to indirect_iterator::reference. Also, +there are further requirements on the +iterator_traits<Iterator>::value_type if the Value parameter +is not use_default, as implied by the algorithm for deducing the +default for the value_type member.
+If CategoryOrTraversal is a standard iterator tag, +indirect_iterator is a model of the iterator concept corresponding +to the tag, otherwise indirect_iterator satisfies the requirements +of the most refined standard traversal concept that is satisfied by +the Iterator argument.
+indirect_iterator models Readable Iterator. If +indirect_iterator::reference(*v) = t is a valid expression (where +t is an object of type indirect_iterator::value_type) then +indirect_iterator models Writable Iterator. If +indirect_iterator::reference is a reference then +indirect_iterator models Lvalue Iterator.
+indirect_iterator();
+Requires: | Iterator must be Default Constructible. | +
---|---|
Returns: | An instance of indirect_iterator with +a default-constructed iterator_adaptor subobject. | +
indirect_iterator(Iterator x);
+Returns: | An instance of indirect_iterator with +the iterator_adaptor subobject copy constructed from x. | +
---|
+template < + class Iterator2, class Value2, unsigned Access, class Traversal + , class Reference2, class Difference2 +> +indirect_iterator( + indirect_iterator< + Iterator2, Value2, Access, Traversal, Reference2, Difference2 + > const& y + , typename enable_if_convertible<Iterator2, Iterator>::type* = 0 // exposition +); ++
Requires: | Iterator2 is implicitly convertible to Iterator. | +
---|---|
Returns: | An instance of indirect_iterator whose +iterator_adaptor subobject is constructed from y.base(). | +
Date: | +2004-01-21 |
---|---|
Copyright: | +Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2003. |
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The proposal includes:
++enum iterator_access { + readable_iterator = 1, writable_iterator = 2, + swappable_iterator = 4, lvalue_iterator = 8 +}; ++
In general, the standard specifies thing like this as a bitmask +type with a list of defined names, and specifies neither the exact +type nor the specific values. Is there a reason for iterator_access +to be more specific?
+Proposed resolution: | |
---|---|
The iterator_access enum will be removed, +so this is no longer an issue. See the resolution to 9.15. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
In general, we've provided operational semantics for things like +operator++. That is, we've said that ++iter must work, without +requiring either a member function or a non-member function. +iterator_facade specifies most operators as member +functions. There's no inherent reason for these to be members, so +we should remove this requirement. Similarly, some operations are +specified as non-member functions but could be implemented as +members. Again, the standard doesn't make either of these choices, +and TR1 shouldn't, either. So: operator*(), operator++(), +operator++(int), operator--(), operator--(int), +operator+=, operator-=, operator-(difference_type), +operator-(iterator_facade instance), and operator+ should +be specified with operational semantics and not explicitly required +to be members or non-members.
+Proposed resolution: | |
---|---|
Not a defect. | +|
Rationale: | The standard uses valid expressions such as ++iter +in requirements tables, such as for input iterator. However, for +classes, such as reverse_iterator, the standard uses function +prototypes, as we have done here for +iterator_facade. Further, the prototype specification does +not prevent the implementor from using members or non-members, +since nothing the user can do in a conforming program can detect +how the function is implemented. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The only discussion of what this means is in a note, so is +non-normative. Further, the note seems to be incorrect. It says +that enable_if_interoperable only works for types that "are +interoperable, by which we mean they are convertible to each +other." This requirement is too strong: it should be that one of +the types is convertible to the other. N1541 48
+Proposed resolution: | |
---|---|
Add normative text. Relax requirements in the +proposed way. +Change: ++[Note: The enable_if_interoperable template used above is +for exposition purposes. The member operators should be only be +in an overload set provided the derived types Dr1 and +Dr2 are interoperable, by which we mean they are +convertible to each other. The enable_if_interoperable +approach uses SFINAE to take the operators out of the overload +set when the types are not interoperable.]+ To: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
In every place where enable_if_convertible is used it's used like +this (simplified):
++template<class T> +struct C +{ + template<class T1> + C(T1, enable_if_convertible<T1, T>::type* = 0); +}; ++
The idea being that this constructor won't compile if T1 isn't +convertible to T. As a result, the constructor won't be considered +as a possible overload when constructing from an object x where the +type of x isn't convertible to T. In addition, however, each of +these constructors has a requires clause that requires +convertibility, so the behavior of a program that attempts such a +construction is undefined. Seems like the enable_if_convertible +part is irrelevant, and should be removed. There are two +problems. First, enable_if_convertible is never specified, so we +don't know what this is supposed to do. Second: we could reasonably +say that this overload should be disabled in certain cases or we +could reasonably say that behavior is undefined, but we can't say +both.
+Thomas Witt writes that the goal of putting in +enable_if_convertible here is to make sure that a specific overload +doesn't interfere with the generic case except when that overload +makes sense. He agrees that what we currently have is deficient. +Dave Abrahams writes that there is no conflict with the requires +cause because the requires clause only takes effect when the +function is actually called. The presence of the constructor +signature can/will be detected by is_convertible without violating +the requires clause, and thus it makes a difference to disable +those constructor instantiations that would be disabled by +enable_if_convertible even if calling them invokes undefined +behavior. There was more discussion on the reflector: +c++std-lib-12312, c++std-lib-12325, c++std-lib- 12330, +c++std-lib-12334, c++std-lib-12335, c++std-lib-12336, +c++std-lib-12338, c++std-lib- 12362.
+Proposed resolution: | |
---|---|
Change: ++[Note: The enable_if_convertible<X,Y>::type expression +used in this section is for exposition purposes. The converting +constructors for specialized adaptors should be only be in an +overload set provided that an object of type X is +implicitly convertible to an object of type Y. The +enable_if_convertible approach uses SFINAE to take the +constructor out of the overload set when the types are not +implicitly convertible.]+ To: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The title says it all; this is probably just a typo.
+Proposed resolution: | |
---|---|
Remove the 'bool'. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
iterator_adaptor has a private member named m_iterator. Presumably +this is for exposition only, since it's an implementation +detail. It needs to be marked as such.
+Proposed resolution: | |
---|---|
In [lib.iterator.adaptor] +Change: ++Base m_iterator; ++ to: ++Base m_iterator; // exposition only ++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
iterator_adpator() has a Requires clause, that Base must be default +constructible. iterator_adaptor(Base) has no Requires clause, +although the Returns clause says that the Base member is copy +construced from the argument (this may actually be an oversight in +N1550, which doesn't require iterators to be copy constructible or +assignable).
+Proposed resolution: | |
---|---|
Add a requirements section for the template +parameters of iterator_adaptor, and state that Base must be Copy +Constructible and Assignable. +N1550 does in fact include requirements for copy constructible +and assignable in the requirements tables. To clarify, we've also +added the requirements to the text. + |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
similar to 9.3, "Specialized Adaptors" has a note describing +enable_if_convertible. This should be normative text.
+Proposed resolution: | |
---|---|
Changed it to normative +text. See the resolution of 9.4 | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
reverse iterator "flips the direction of the base iterator's +motion". This needs to be more formal, as in the current +standard. Something like: "iterates through the controlled sequence +in the opposite direction"
+Proposed resolution: | |
---|---|
Change: ++The reverse iterator adaptor flips the direction of a base +iterator's motion. Invoking operator++() moves the base +iterator backward and invoking operator--() moves the base +iterator forward.+ to: ++The reverse iterator adaptor iterates through the adapted iterator +range in the opposite direction.+ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
reverse_iterator::dereference is specified as calling a function +named 'prior' which has no specification.
+Proposed resolution: | |||
---|---|---|---|
Change the specification to avoid using prior as follows. +Remove: ++typename reverse_iterator::reference dereference() const { return *prior(this->base()); } ++ And at the end of the operations section add: +++ |
+|||
Rationale: | The style of specification has changed because of issue 9.37x. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
Transform iterator has a two-part specification: it does this, in +other words, it does that. "In other words" always means "I didn't +say it right, so I'll try again." We need to say it once.
+Proposed resolution: | |
---|---|
Change: ++The transform iterator adapts an iterator by applying some function +object to the result of dereferencing the iterator. In other words, +the operator* of the transform iterator first dereferences the +base iterator, passes the result of this to the function object, and +then returns the result.+ to: ++The transform iterator adapts an iterator by modifying the +operator* to apply a function object to the result of +dereferencing the iterator and returning the result.+ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
transform_iterator has a private member named 'm_f' which should be +marked "exposition only."
+Proposed resolution: | |
---|---|
Mark the member m_f as exposition +only. Note/DWA: I think this is NAD because the user can't +detect it, though I'm happy to mark it exposition only. +Change: ++UnaryFunction m_f; ++ to: ++UnaryFunction m_f; // exposition only ++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The description of Counting iterator is unclear. "The counting +iterator adaptor implements dereference by returning a reference to +the base object. The other operations are implemented by the base +m_iterator, as per the inheritance from iterator_adaptor."
+Proposed resolution: | |
---|---|
Change: ++The counting iterator adaptor implements dereference by +returning a reference to the base object. The other operations +are implemented by the base m_iterator, as per the +inheritance from iterator_adaptor.+ to: ++counting_iterator adapts an object by adding an +operator* that returns the current value of the object. All +other iterator operations are forwarded to the adapted object.+ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
Counting iterator has the following note:
++[Note: implementers are encouraged to provide an implementation +of distance_to and a difference_type that avoids overflows in the +cases when the Incrementable type is a numeric type.]+
I'm not sure what this means. The user provides a template argument +named Difference, but there's no difference_type. I assume this is +just a glitch in the wording. But if implementors are encouraged to +ignore this argument if it won't work right, why is it there?
+Proposed resolution: | |
---|---|
The difference_type was inherited from +iterator_adaptor. However, we've removed the explicit +inheritance, so explicit typedefs have been added. See the +resolution of 9.37x. | +
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
Shortly after N1550 was accepted, we discovered that an iterator's +lvalueness can be determined knowing only its value_type. This +predicate can be calculated even for old-style iterators (on whose +reference type the standard places few requirements). A trait in +the Boost iterator library does it by relying on the compiler's +unwillingness to bind an rvalue to a T& function template +parameter. Similarly, it is possible to detect an iterator's +readability knowing only its value_type. Thus, any interface which +asks the user to explicitly describe an iterator's lvalue-ness or +readability seems to introduce needless complexity.
+Proposed resolution: | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
In N1550: +Remove: +++ After: ++Like the old iterator requirements, we provide tags for +purposes of dispatching based on the traversal concepts. The +tags are related via inheritance so that a tag is convertible +to another tag if the concept associated with the first tag is +a refinement of the second tag.+ Add: +++ From the Readable Iterator Requirements table, remove: +++ From the Writable Iterator Requirements table, remove: +++ From the Swappable Iterator Requirements table, remove: +++ From [lib.iterator.synopsis] replace: ++template <class Iterator> struct is_readable; +template <class Iterator> struct is_writable; +template <class Iterator> struct is_swappable; +template <class Iterator> struct traversal_category; + +enum iterator_access { readable_iterator = 1, writable_iterator = 2, + swappable_iterator = 4, lvalue_iterator = 8 }; + +template <unsigned int access_bits, class TraversalTag> +struct iterator_tag : /* appropriate old category or categories */ { + static const iterator_access access = + (iterator_access)access_bits & + (readable_iterator | writable_iterator | swappable_iterator); + typedef TraversalTag traversal; +}; ++ with: ++template <class Iterator> struct is_readable_iterator; +template <class Iterator> struct iterator_traversal; ++ In [lib.iterator.traits], remove: +++ Change: +++ to: +++ In N1530: +In [lib.iterator.helper.synopsis]: +Change: ++const unsigned use_default_access = -1; + +struct iterator_core_access { /* implementation detail */ }; + +template < + class Derived + , class Value + , unsigned AccessCategory + , class TraversalCategory + , class Reference = Value& + , class Difference = ptrdiff_t +> +class iterator_facade; + +template < + class Derived + , class Base + , class Value = use_default + , unsigned Access = use_default_access + , class Traversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class iterator_adaptor; + +template < + class Iterator + , class Value = use_default + , unsigned Access = use_default_access + , class Traversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class indirect_iterator; ++ To: ++struct iterator_core_access { /* implementation detail */ }; + +template < + class Derived + , class Value + , class CategoryOrTraversal + , class Reference = Value& + , class Difference = ptrdiff_t +> +class iterator_facade; + +template < + class Derived + , class Base + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class iterator_adaptor; + +template < + class Iterator + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class indirect_iterator; ++ Change: ++template < + class Incrementable + , unsigned Access = use_default_access + , class Traversal = use_default + , class Difference = use_default +> +class counting_iterator ++ To: ++template < + class Incrementable + , class CategoryOrTraversal = use_default + , class Difference = use_default +> +class counting_iterator; ++ In [lib.iterator.facade]: +Change: ++template < + class Derived + , class Value + , unsigned AccessCategory + , class TraversalCategory + , class Reference = /* see below */ + , class Difference = ptrdiff_t +> +class iterator_facade { ++ to: ++template < + class Derived + , class Value + , class CategoryOrTraversal + , class Reference = Value& + , class Difference = ptrdiff_t +> +class iterator_facade { ++ Change: ++typedef iterator_tag<AccessCategory, TraversalCategory> iterator_category; ++ to: ++typedef /* see below */ iterator_category; ++ Change: ++// Comparison operators +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type // exposition +operator ==(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator !=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator <(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator <=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator >(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator >=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator >=(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +// Iterator difference +template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, + class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator -(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, + iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); + +// Iterator addition +template <class Derived, class V, class AC, class TC, class R, class D> +Derived operator+ (iterator_facade<Derived, V, AC, TC, R, D> const&, + typename Derived::difference_type n) ++ to: ++// Comparison operators +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type // exposition +operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +// Iterator difference +template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +/* see below */ +operator-(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); + +// Iterator addition +template <class Dr, class V, class TC, class R, class D> +Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, + typename Derived::difference_type n); + +template <class Dr, class V, class TC, class R, class D> +Derived operator+ (typename Derived::difference_type n, + iterator_facade<Dr,V,TC,R,D> const&); ++ After the iterator_facade synopsis, add: +The iterator_category member of iterator_facade is ++iterator-category(CategoryOrTraversal, value_type, reference) ++ where iterator-category is defined as follows: ++iterator-category(C,R,V) := + if (C is convertible to std::input_iterator_tag + || C is convertible to std::output_iterator_tag + ) + return C + + else if (C is not convertible to incrementable_traversal_tag) + the program is ill-formed + + else return a type X satisfying the following two constraints: + + 1. X is convertible to X1, and not to any more-derived + type, where X1 is defined by: + + if (R is a reference type + && C is convertible to forward_traversal_tag) + { + if (C is convertible to random_access_traversal_tag) + X1 = random_access_iterator_tag + else if (C is convertible to bidirectional_traversal_tag) + X1 = bidirectional_iterator_tag + else + X1 = forward_iterator_tag + } + else + { + if (C is convertible to single_pass_traversal_tag + && R is convertible to V) + X1 = input_iterator_tag + else + X1 = C + } + + 2. category-to-traversal(X) is convertible to the most + derived traversal tag type to which X is also + convertible, and not to any more-derived traversal tag + type. ++ |
+
++In [lib.iterator.facade] iterator_facade requirements:
+Remove:
++AccessCategory must be an unsigned value which uses no more +bits than the greatest value of iterator_access.+In the Iterator Adaptor section, change:
++Several of the template parameters of iterator_adaptor default +to use_default (or use_default_access).+to:
++Several of the template parameters of iterator_adaptor default +to use_default.+In [lib.iterator.special.adaptors]:
+Change:
++template < + class Iterator + , class Value = use_default + , unsigned Access = use_default_access + , class Traversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class indirect_iterator ++to:
++template < + class Iterator + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class indirect_iterator ++Change:
++template < + class Iterator2, class Value2, unsigned Access2, class Traversal2 + , class Reference2, class Difference2 +> +indirect_iterator( ++to:
++template < + class Iterator2, class Value2, class Category2 + , class Reference2, class Difference2 +> +indirect_iterator( ++Change:
++template < + class Incrementable + , unsigned Access = use_default_access + , class Traversal = use_default + , class Difference = use_default +> +class counting_iterator ++to:
++template < + class Incrementable + , class CategoryOrTraversal = use_default + , class Difference = use_default +> +class counting_iterator ++Change:
++typedef iterator_tag< + writable_iterator + , incrementable_traversal_tag +> iterator_category; ++to:
++typedef std::output_iterator_tag iterator_category;+In [lib.iterator.adaptor]
+Change:
++template < + class Derived + , class Base + , class Value = use_default + , unsigned Access = use_default_access + , class Traversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class iterator_adaptor ++To:
++template < + class Derived + , class Base + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class iterator_adaptor ++
Rationale: | + |
---|
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
is_writable_iterator returns false positives for forward iterators +whose value_type has a private assignment operator, or whose +reference type is not a reference (currently legal).
+Proposed Resolution: | |
---|---|
See the resolution to 9.15. | +
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
is_swappable_iterator has the same problems as +is_writable_iterator. In addition, if we allow users to write their +own iter_swap functions it's easy to imagine old-style iterators +for which is_swappable returns false negatives.
+Proposed Resolution: | |
---|---|
See the resolution to 9.15. | +
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
I am concerned that there is little use for any of is_readable, +is_writable, or is_swappable, and that not only do they unduly +constrain iterator implementors but they add overhead to +iterator_facade and iterator_adaptor in the form of a template +parameter which would otherwise be unneeded. Since we can't +implement two of them accurately for old-style iterators, I am +having a hard time justifying their impact on the rest of the +proposal(s).
+Proposed Resolution: | |
---|---|
See the resolution to 9.15. | +
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
The proposed iterator_tag class template accepts an "access bits" +parameter which includes a bit to indicate the iterator's +lvalueness (whether its dereference operator returns a reference to +its value_type. The relevant part of N1550 says:
++The purpose of the lvalue_iterator part of the iterator_access +enum is to communicate to iterator_tagwhether the reference type +is an lvalue so that the appropriate old category can be chosen +for the base class. The lvalue_iterator bit is not recorded in +the iterator_tag::access data member.+
The lvalue_iterator bit is not recorded because N1550 aims to +improve orthogonality of the iterator concepts, and a new-style +iterator's lvalueness is detectable by examining its reference +type. This inside/outside difference is awkward and confusing.
+Proposed Resolution: | |
---|---|
The iterator_tag class will be removed, so this is no longer an issue. +See the resolution to 9.15. | +
Submitter: | Dave Abrahams | +
---|---|
Status: | New | +
Howard Hinnant pointed out some inconsistencies with the naming of +these tag types:
++incrementable_iterator_tag // ++r, r++ +single_pass_iterator_tag // adds a == b, a != b +forward_traversal_iterator_tag // adds multi-pass +bidirectional_traversal_iterator_tag // adds --r, r-- +random_access_traversal_iterator_tag // adds r+n,n+r,etc. ++
Howard thought that it might be better if all tag names contained +the word "traversal". It's not clear that would result in the best +possible names, though. For example, incrementable iterators can +only make a single pass over their input. What really distinguishes +single pass iterators from incrementable iterators is not that they +can make a single pass, but that they are equality +comparable. Forward traversal iterators really distinguish +themselves by introducing multi-pass capability. Without entering +a "Parkinson's Bicycle Shed" type of discussion, it might be worth +giving the names of these tags (and the associated concepts) some +extra attention.
+Proposed resolution: | |||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Change the names of the traversal tags to the +following names: ++incrementable_traversal_tag +single_pass_traversal_tag +forward_traversal_tag +bidirectional_traversal_tag +random_access_traversal_tag ++ In [lib.iterator.traversal]: +Change: +++ to: +++ Change: +++ to: +++ Change: +++ to: +++ Change: +++ to: +++ Change: +++ to: +++ In [lib.iterator.synopsis], change: ++struct incrementable_iterator_tag { }; +struct single_pass_iterator_tag : incrementable_iterator_tag { }; +struct forward_traversal_tag : single_pass_iterator_tag { }; ++ to: ++struct incrementable_traversal_tag { }; +struct single_pass_traversal_tag : incrementable_traversal_tag { }; +struct forward_traversal_tag : single_pass_traversal_tag { }; ++ Remove: ++struct null_category_tag { }; +struct input_output_iterator_tag : input_iterator_tag, output_iterator_tag {}; ++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The first template argument to iterator_facade is named Derived, +and the proposal says:
++The Derived template parameter must be a class derived from +iterator_facade.+
First, iterator_facade is a template, so cannot be derived +from. Rather, the class must be derived from a specialization of +iterator_facade. More important, isn't Derived required to be the +class that is being defined? That is, if I understand it right, the +definition of D here this is not valid:
++class C : public iterator_facade<C, ... > { ... }; +class D : public iterator_facade<C, ...> { ... }; ++
In the definition of D, the Derived argument to iterator_facade is +a class derived from a specialization of iterator_facade, so the +requirement is met. Shouldn't the requirement be more like "when +using iterator_facade to define an iterator class Iter, the class +Iter must be derived from a specialization of iterator_facade whose +first template argument is Iter." That's a bit awkward, but at the +moment I don't see a better way of phrasing it.
+Proposed resolution: | |
---|---|
In [lib.iterator.facade] +Remove: ++The Derived template parameter must be a class derived from +iterator_facade.+ Change: ++The following table describes the other requirements on the +Derived parameter. Depending on the resulting iterator's +iterator_category, a subset of the expressions listed in the table +are required to be valid. The operations in the first column must be +accessible to member functions of class iterator_core_access.+ to: ++The following table describes the typical valid expressions on +iterator_facade's Derived parameter, depending on the +iterator concept(s) it will model. The operations in the first +column must be made accessible to member functions of class +iterator_core_access. In addition, +static_cast<Derived*>(iterator_facade*) shall be well-formed.+ In [lib.iterator.adaptor] +Change: ++The iterator_adaptor is a base class template derived from +an instantiation of iterator_facade.+ to: ++Each specialization of the iterator_adaptor class template +is derived from a specialization of iterator_facade.+ Change: ++The Derived template parameter must be a derived class of +iterator_adaptor.+ To: ++static_cast<Derived*>(iterator_adaptor*) shall be well-formed.+ |
+
[Note: The proposed resolution to Issue 9.37 contains related +changes]
+Submitter: | Pete Becker | +
---|---|
Status: | New | +
The proposal says:
++template <class Dr1, class V1, class AC1, class TC1, class R1, class D1, +class Dr2, class V2, class AC2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1, Dr2, bool>::type +operator -(iterator_facade<Dr1, V1, AC1, TC1, R1, D1> const& lhs, +iterator_facade<Dr2, V2, AC2, TC2, R2, D2> const& rhs); ++
Shouldn't the return type be one of the two iterator types? Which +one? The idea is that if one of the iterator types can be converted +to the other type, then the subtraction is okay. Seems like the +return type should then be the type that was converted to. Is that +right?
+Proposed resolution: | |
---|---|
See resolution to 9.34. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
In the table that lists the required (sort of) member functions of +iterator types that are based on iterator_facade, the entry for +c.equal(y) says:
++true iff c and y refer to the same position. Implements c == y +and c != y. The second sentence is inside out. c.equal(y) does +not implement either of these operations. It is used to implement +them. Same thing in the description of c.distance_to(z).+
Proposed resolution: | |
---|---|
remove "implements" descriptions from +table. See resolution to 9.34 | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
Several of the descriptions use the name X without defining +it. This seems to be a carryover from the table immediately above +this section, but the text preceding that table says "In the table +below, X is the derived iterator type." Looks like the X:: +qualifiers aren't really needed; X::reference can simply be +reference, since that's defined by the iterator_facade +specialization itself.
+Proposed resolution: | |||||
---|---|---|---|---|---|
Remove references to X. +In [lib.iterator.facade] operations operator->() const;: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
Several of the member functions return a Derived object or a +Derived&. Their Effects clauses end with:
++return *this; ++
This should be
++return *static_cast<Derived*>(this); ++
Proposed resolution: | |
---|---|
In [lib.iterator.facade], in the effects clause +of the following operations: ++Derived& operator++() +Derived& operator--() +Derived& operator+=(difference_type n) +Derived& operator-=(difference_type n) ++
|
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The returns clause for operator[](difference_type n) const +says:
++Returns: an object convertible to X::reference and holding a copy +p of a+n such that, for a constant object v of type +X::value_type, X::reference(a[n] = v) is equivalent to p = v. +This needs to define 'a', but assuming it's supposed to be +*this (or maybe *(Derived*)this), it still isn't clear +what this says. Presumably, the idea is that you can index off of +an iterator and assign to the result. But why the requirement +that it hold a copy of a+n? Granted, that's probably how it's +implemented, but it seems over-constrained. And the last phrase +seems wrong. p is an iterator; there's no requirement that you +can assign a value_type object to it. Should that be *p = v? +But why the cast in reference(a[n] = v)?+
Proposed resolution: | |||||
---|---|---|---|---|---|
In section operator[]: +++ In [lib.iterator.facade] operations: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
operator- has both an effects clause and a returns +clause. Looks like the returns clause should be removed.
+Proposed resolution: | |||
---|---|---|---|
Remove the returns clause. +In [lib.iterator.facade] operations: +
|
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The default constructor returns "An instance of indirect_iterator +with a default constructed base object", but the constructor that +takes an Iterator object returns "An instance of indirect_iterator +with the iterator_adaptor subobject copy constructed from x." The +latter is the correct form, since it does not reach inside the base +class for its semantics. So the default constructor shoudl return +"An instance of indirect_iterator with a default-constructed +iterator_adaptor subobject."
+Proposed resolution: | |||||
---|---|---|---|---|---|
|
+|||||
Rationale: | Inheritance from iterator_adaptor has been removed, so we instead +give the semantics in terms of the (exposition only) member +m_iterator. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The templated constructor that takes an indirect_iterator with a +different set of template arguments says that it returns "An +instance of indirect_iterator that is a copy of [the argument]". +But the type of the argument is different from the type of the +object being constructed, and there is no description of what +a "copy" means. The Iterator template parameter for the argument +must be convertible to the Iterator template parameter for the type +being constructed, which suggests that the argument's contained +Iterator object should be converted to the target type's Iterator +type. Is that what's meant here? +(Pete later writes: In fact, this problem is present in all of the +specialized adaptors that have a constructor like this: the +constructor returns "a copy" of the argument without saying what a +copy is.)
+Proposed resolution: | |||||
---|---|---|---|---|---|
|
+|||||
Rationale: | Inheritance from iterator_adaptor has been removed, so we +instead give the semantics in terms of the member m_iterator. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
The specialized adaptors that take both a Value and a Reference +template argument all take them in that order, i.e. Value precedes +Reference in the template argument list, with the exception of +transform_iterator, where Reference precedes Value. This seems like +a possible source of confusion. Is there a reason why this order is +preferable?
+Proposed resolution: | |
---|---|
NAD | +|
Rationale: | defaults for Value depend on Reference. A sensible +Value can almost always be computed from Reference. The first +parameter is UnaryFunction, so the argument order is already +different from the other adapters. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
function_output_iterator requirements says: "The UnaryFunction must +be Assignable, Copy Constructible, and the expression f(x) must be +valid, where f is an object of type UnaryFunction and x is an +object of a type accepted by f."
+Everything starting with "and," somewhat reworded, is actually a +constraint on output_proxy::operator=. All that's needed to create +a function_output_iterator object is that the UnaryFunction type be +Assignable and CopyConstructible. That's also sufficient to +dereference and to increment such an object. It's only when you try +to assign through a dereferenced iterator that f(x) has to work, +and then only for the particular function object that the iterator +holds and for the particular value that is being assigned.
+Proposed resolution: | |
---|---|
After function_output_iterator& operator++(int); add: ++private: + UnaryFunction m_f; // exposition only ++
After the requirements section, add: + |
+
function_output_iterator models
++function_output_iterator is a model of the Writable and +Incrementable Iterator concepts.+
Returns: | An instance of function_output_iterator with +f stored as a data member. | +
---|
Effects: | Constructs an instance of function_output_iterator +with m_f constructed from f. | +
---|
output_proxy operator*();
+Returns: | An instance of output_proxy constructed with +a copy of the unary function f. | +
---|
operator*();
+Returns: | An object r of unspecified type such that r = t +is equivalent to m_f(t) for all t. | +
---|
function_output_iterator::output_proxy operations
+output_proxy(UnaryFunction& f);
+Returns: | An instance of output_proxy with f stored as +a data member. | +
---|
template <class T> output_proxy& operator=(const T& value);
+Effects: | +m_f(value); +return *this; ++ |
+
---|
Change:
++explicit function_output_iterator(const UnaryFunction& f = UnaryFunction()); ++
to:
++explicit function_output_iterator(); + +explicit function_output_iterator(const UnaryFunction& f); ++
Submitter: | Pete Becker | +
---|---|
Status: | New | +
This means someone can store an output_proxy object for later use, +whatever that means. It also constrains output_proxy to hold a copy +of the function object, rather than a pointer to the iterator +object. Is all this mechanism really necessary?
+Proposed resolution: | |
---|---|
See issue 9.31. | +
Submitter: | Pete Becker | +
---|---|
Status: | New | +
c++std-lib-12333:
++N1550 requires that for a Readable Iterator a of type X, *a +returns an object of type +iterator_traits<X>::reference. istreambuf_iterator::operator* +returns charT, but istreambuf_iterator::reference is +charT&. So am I overlooking something, or is +istreambuf_iterator not Readable.+
Proposed resolution: | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Remove all constraints on +iterator_traits<X>::reference in Readable Iterator and Lvalue +Iterator. Change Lvalue Iterator to refer to T& instead of +iterator_traits<X>::reference. +
From the Input Iterator Requirements table, remove: +++ Change: +++ to: +++
Change: +++ to: +++ At the end of the section reverse_iterator models, add: +The type iterator_traits<Iterator>::reference must be the type of +*i, where i is an object of type Iterator. + |
+||||||||||||||||||||||||||||
Rationale: | Ideally there should be requirements on the reference +type, however, since Readable Iterator is suppose to correspond +to the current standard iterator requirements (which do not place +requirements on the reference type) we will leave them off for +now. There is a DR in process with respect to the reference type +in the stadard iterator requirements. Once that is resolved we +will revisit this issue for Readable Iterator and Lvalue +Iterator. +We added Assignable to the requirements for Readable +Iterator. This is needed to have Readable Iterator coincide with +the capabilities of Input Iterator. + |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
c++std-lib-12562:
++The template functions operator==, operator!=, +operator<, operator<=, operator>, operator>=, and +operator- that take two arguments that are specializations of +iterator_facade have no specification. The template function +operator+ that takes an argument that is a specialization of +iterator_facade and an argument of type difference_type has no +specification.+
Proposed resolution: | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Add the missing specifications. ++template <class Dr, class V, class TC, class R, class D> +Derived operator+ (iterator_facade<Dr,V,TC,R,D> const&, + typename Derived::difference_type n); + +template <class Dr, class V, class TC, class R, class D> +Derived operator+ (typename Derived::difference_type n, + iterator_facade<Dr,V,TC,R,D> const&); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator ==(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator !=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator <(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator <=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator >(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,bool>::type +operator >=(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
+template <class Dr1, class V1, class TC1, class R1, class D1, + class Dr2, class V2, class TC2, class R2, class D2> +typename enable_if_interoperable<Dr1,Dr2,difference>::type +operator -(iterator_facade<Dr1,V1,TC1,R1,D1> const& lhs, + iterator_facade<Dr2,V2,TC2,R2,D2> const& rhs); ++
|
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
c++std-lib-12563:
+++The table listing the functions required for types derived from +iterator_facade has two functions named equal and two named +distance_to:
++c.equal(b) +c.equal(y) +c.distance_to(b) +c.distance_to(z) ++where b and c are const objects of the derived type, y and z are +constant objects of certain iterator types that are interoperable +with the derived type. Seems like the 'b' versions are +redundant: in both cases, the other version will take a 'b'. In +fact, iterator_adaptor is specified to use iterator_facade, but +does not provide the 'b' versions of these functions.
+Are the 'b' versions needed?
+
Proposed resolution: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Remove the 'b' versions. +In iterator_facade requirements, remove: +++ and remove: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
c++std-lib-12636:
+++The table that lists required functions for the derived type X +passed to iterator_facade lists, among others:
+for a single pass iterator:
++c.equal(b) +c.equal(y) ++where b and c are const X objects, and y is a const object of a +single pass iterator that is interoperable with X. Since X is +interoperable with itself, c.equal(b) is redundant. There is a +difference in their descriptions, but its meaning isn't +clear. The first is "true iff b and c are equivalent", and the +second is "true iff c and y refer to the same position." Is there +a difference between the undefined term "equivalent" and "refer +to the same position"?
+Similarly, for a random access traversal iterator:
++c.distance_to(b) +c.distance_to(z) ++where z is a constant object of a random access traversal +iterator that is interoperable with X. Again, X is interoperable +with itself, so c.distance_to(b) is redundant. Also, the +specification for c.distance_to(z) isn't valid. It's written +as "equivalent to distance(c, z)". The template function distance +takes two arguments of the same type, so distance(c, z) isn't +valid if c and z are different types. Should it be +distance(c, (X)z)?
+
Proposed resolution: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Removed the 'b' versions (see 9.35) and added the cast. +Change: +++ to: +++ |
+
Submitter: | Pete Becker | +
---|---|
Status: | New | +
c++std-lib-12696: +The paper requires that iterator_adaptor be derived from an +appropriate instance of iterator_facade, and that most of the specific +forms of adaptors be derived from appropriate instances of +iterator_adaptor. That seems like overspecification, and we ought to +look at specifying these things in terms of what the various templates +provide rather than how they're implemented.
+Proposed resolution: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Remove the specfication of inheritance, and add explicit +specification of all the functionality that was inherited from the +specialized iterators. +In iterator_adaptor, inheritance is retained, sorry NAD. Also, +the Interoperable Iterators concept is added to the new iterator +concepts, and this concept is used in the specification of the +iterator adaptors. +In n1550, after [lib.random.access.traversal.iterators], add: +++ In N1530: +++ |
+
iterator_adaptor base class parameters
+++The V', C', R', and D' parameters of the iterator_facade +used as a base class in the summary of iterator_adaptor +above are defined as follows:
++V' = if (Value is use_default) + return iterator_traits<Base>::value_type + else + return Value + +C' = if (CategoryOrTraversal is use_default) + return iterator_traversal<Base>::type + else + return CategoryOrTraversal + +R' = if (Reference is use_default) + if (Value is use_default) + return iterator_traits<Base>::reference + else + return Value& + else + return Reference + +D' = if (Difference is use_default) + return iterator_traits<Base>::difference_type + else + return Difference ++
In [lib.iterator.special.adaptors]
+Change:
++class indirect_iterator + : public iterator_adaptor</* see discussion */> +{ + friend class iterator_core_access; ++
to:
++class indirect_iterator +{ + public: + typedef /* see below */ value_type; + typedef /* see below */ reference; + typedef /* see below */ pointer; + typedef /* see below */ difference_type; + typedef /* see below */ iterator_category; ++
Change:
++private: // as-if specification + typename indirect_iterator::reference dereference() const + { + return **this->base(); + } ++
to:
++ Iterator const& base() const; + reference operator*() const; + indirect_iterator& operator++(); + indirect_iterator& operator--(); +private: + Iterator m_iterator; // exposition ++
After the synopsis add:
+++The member types of indirect_iterator are defined +according to the following pseudo-code, where V is +iterator_traits<Iterator>::value_type
++if (Value is use_default) then + typedef remove_const<pointee<V>::type>::type value_type; +else + typedef remove_const<Value>::type value_type; + +if (Reference is use_default) then + if (Value is use_default) then + typedef indirect_reference<V>::type reference; + else + typedef Value& reference; +else + typedef Reference reference; + +if (Value is use_default) then + typedef pointee<V>::type* pointer; +else + typedef Value* pointer; + +if (Difference is use_default) + typedef iterator_traits<Iterator>::difference_type difference_type; +else + typedef Difference difference_type; + +if (CategoryOrTraversal is use_default) + typedef iterator-category( + iterator_traversal<Iterator>::type,``reference``,``value_type`` + ) iterator_category; +else + typedef iterator-category( + CategoryOrTraversal,``reference``,``value_type`` + ) iterator_category; ++
[Note: See resolution to 9.44y for a description of pointee and +indirect_reference]
+After the requirements section, add:
+indirect_iterator models
+++In addition to the concepts indicated by iterator_category +and by iterator_traversal<indirect_iterator>::type, a +specialization of indirect_iterator models the following +concepts, Where v is an object of +iterator_traits<Iterator>::value_type:
++++
+- Readable Iterator if reference(*v) is convertible to +value_type.
+- Writable Iterator if reference(*v) = t is a valid +expression (where t is an object of type +indirect_iterator::value_type)
+- Lvalue Iterator if reference is a reference type.
+indirect_iterator<X,V1,C1,R1,D1> is interoperable with +indirect_iterator<Y,V2,C2,R2,D2> if and only if X is +interoperable with Y.
+
Before indirect_iterator(); add:
++In addition to the operations required by the concepts described +above, specializations of indirect_iterator provide the +following operations.+
Returns: | An instance of indirect_iterator with +the iterator_adaptor subobject copy constructed from x. | +
---|
Returns: | An instance of indirect_iterator with +m_iterator copy constructed from x. | +
---|
At the end of the indirect_iterator operations add:
+++Iterator const& base() const;
++
++ + + + + Returns: m_iterator +reference operator*() const;
++
++ + + + + Returns: **m_iterator +indirect_iterator& operator++();
++
++ + + + Effects: ++m_iterator ++ + Returns: *this +indirect_iterator& operator--();
++
++ + + + Effects: --m_iterator ++ + Returns: *this +
Change:
++template <class Iterator> +class reverse_iterator : + public iterator_adaptor< reverse_iterator<Iterator>, Iterator > +{ + friend class iterator_core_access; ++
to:
++template <class Iterator> +class reverse_iterator +{ +public: + typedef iterator_traits<Iterator>::value_type value_type; + typedef iterator_traits<Iterator>::reference reference; + typedef iterator_traits<Iterator>::pointer pointer; + typedef iterator_traits<Iterator>::difference_type difference_type; + typedef /* see below */ iterator_category; ++
Change:
++private: // as-if specification + typename reverse_iterator::reference dereference() const { return *prior(this->base()); } + + void increment() { --this->base_reference(); } + void decrement() { ++this->base_reference(); } + + void advance(typename reverse_iterator::difference_type n) + { + this->base_reference() += -n; + } + + template <class OtherIterator> + typename reverse_iterator::difference_type + distance_to(reverse_iterator<OtherIterator> const& y) const + { + return this->base_reference() - y.base(); + } ++
to:
++ Iterator const& base() const; + reference operator*() const; + reverse_iterator& operator++(); + reverse_iterator& operator--(); +private: + Iterator m_iterator; // exposition ++
reverse_iterator requirements
+The base Iterator must be a model of Bidirectional Traversal +Iterator. The resulting reverse_iterator will be a model of the +most refined standard traversal and access concepts that are modeled +by Iterator.
+reverse_iterator requirements
+Iterator must be a model of Bidirectional Traversal Iterator.
+reverse_iterator models
+++A specialization of reverse_iterator models the same iterator +traversal and iterator access concepts modeled by its Iterator +argument. In addition, it may model old iterator concepts +specified in the following table:
++
++ + ++ + + + + If I models +then reverse_iterator<I> models ++ Readable Lvalue Iterator, +Bidirectional Traversal Iterator +Bidirectional Iterator ++ Writable Lvalue Iterator, +Bidirectional Traversal Iterator +Mutable Bidirectional Iterator ++ Readable Lvalue Iterator, +Random Access Traversal Iterator +Random Access Iterator ++ + Writable Lvalue Iterator, +Random Access Traversal Iterator +Mutable Random Access Iterator +reverse_iterator<X> is interoperable with +reverse_iterator<Y> if and only if X is interoperable with +Y.
+
Returns: | An instance of reverse_iterator with a +default constructed base object. | +
---|
Effects: | Constructs an instance of reverse_iterator with m_iterator +default constructed. | +
---|
Effects: | Constructs an instance of reverse_iterator with a +base object copy constructed from x. | +
---|
Effects: | Constructs an instance of reverse_iterator with a +m_iterator constructed from x. | +
---|
Returns: | An instance of reverse_iterator that is a copy of r. | +
---|
Effects: | Constructs instance of reverse_iterator whose +m_iterator subobject is constructed from y.base(). | +
---|
Iterator const& base() const;
+Returns: | m_iterator | +
---|
reference operator*() const;
+Effects: | + |
---|
+Iterator tmp = m_iterator; +return *--tmp; ++
reverse_iterator& operator++();
+Effects: | --m_iterator | +
---|---|
Returns: | *this | +
reverse_iterator& operator--();
+Effects: | ++m_iterator | +
---|---|
Returns: | *this | +
Change:
++class transform_iterator + : public iterator_adaptor</* see discussion */> +{ + friend class iterator_core_access; ++
to:
++class transform_iterator +{ +public: + typedef /* see below */ value_type; + typedef /* see below */ reference; + typedef /* see below */ pointer; + typedef iterator_traits<Iterator>::difference_type difference_type; + typedef /* see below */ iterator_category; ++
After UnaryFunction functor() const; add:
++Iterator const& base() const; +reference operator*() const; +transform_iterator& operator++(); +transform_iterator& operator--(); ++
Change:
++private: + typename transform_iterator::value_type dereference() const; + UnaryFunction m_f; +}; ++
to:
++private: + Iterator m_iterator; // exposition only + UnaryFunction m_f; // exposition only +}; ++
The type Iterator must at least model Readable Iterator. The +resulting transform_iterator models the most refined of the +following that is also modeled by Iterator.
++++
+- Writable Lvalue Iterator if +result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type +is a non-const reference.
+- Readable Lvalue Iterator if +result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type +is a const reference.
+- Readable Iterator otherwise.
+
The transform_iterator models the most refined standard traversal +concept that is modeled by Iterator.
+The reference type of transform_iterator is +result_of<UnaryFunction(iterator_traits<Iterator>::reference)>::type. +The value_type is remove_cv<remove_reference<reference> >::type.
+After the requirements section, add:
+transform_iterator models
+++The resulting transform_iterator models the most refined of the +following options that is also modeled by Iterator.
++++
+- Writable Lvalue Iterator if +transform_iterator::reference is a non-const +reference.
+- Readable Lvalue Iterator if +transform_iterator::reference is a const reference.
+- Readable Iterator otherwise.
+The transform_iterator models the most refined standard traversal +concept that is modeled by the Iterator argument.
+If transform_iterator is a model of Readable Lvalue Iterator then +it models the following original iterator concepts depending on what +the Iterator argument models.
++
++ + ++ + + + + If Iterator models +then transform_iterator models ++ Single Pass Iterator +Input Iterator ++ Forward Traversal Iterator +Forward Iterator ++ Bidirectional Traversal Iterator +Bidirectional Iterator ++ + Random Access Traversal Iterator +Random Access Iterator +If transform_iterator models Writable Lvalue Iterator then it is a +mutable iterator (as defined in the old iterator requirements).
+transform_iterator<F1, X, R1, V1> is interoperable with +transform_iterator<F2, Y, R2, V2> if and only if X is +interoperable with Y.
+
Remove the private operations section heading and remove:
++``typename transform_iterator::value_type dereference() const;`` + +:Returns: ``m_f(transform_iterator::dereference());`` ++
After the entry for functor(), add:
++``Iterator const& base() const;`` + +:Returns: ``m_iterator`` + + +``reference operator*() const;`` + +:Returns: ``m_f(*m_iterator)`` + + +``transform_iterator& operator++();`` + +:Effects: ``++m_iterator`` +:Returns: ``*this`` + + +``transform_iterator& operator--();`` + +:Effects: ``--m_iterator`` +:Returns: ``*this`` ++
Change:
++template <class Predicate, class Iterator> +class filter_iterator + : public iterator_adaptor< + filter_iterator<Predicate, Iterator>, Iterator + , use_default + , /* see details */ + > +{ + public: ++
to:
++template <class Predicate, class Iterator> +class filter_iterator +{ + public: + typedef iterator_traits<Iterator>::value_type value_type; + typedef iterator_traits<Iterator>::reference reference; + typedef iterator_traits<Iterator>::pointer pointer; + typedef iterator_traits<Iterator>::difference_type difference_type; + typedef /* see below */ iterator_category; ++
Change:
++private: // as-if specification + void increment() + { + ++(this->base_reference()); + satisfy_predicate(); + } + + void satisfy_predicate() + { + while (this->base() != this->m_end && !this->m_predicate(*this->base())) + ++(this->base_reference()); + } + + Predicate m_predicate; + Iterator m_end; ++
to:
++ Iterator const& base() const; + reference operator*() const; + filter_iterator& operator++(); +private: + Predicate m_pred; // exposition only + Iterator m_iter; // exposition only + Iterator m_end; // exposition only ++
After the requirements section, add:
+filter_iterator models
+++The concepts that filter_iterator models are dependent on which +concepts the Iterator argument models, as specified in the +following tables.
++
++ + ++ + + + + If Iterator models +then filter_iterator models ++ Single Pass Iterator +Single Pass Iterator ++ + Forward Traversal Iterator +Forward Traversal Iterator ++
++ + ++ + + + + If Iterator models +then filter_iterator models ++ Readable Iterator +Readable Iterator ++ Writable Iterator +Writable Iterator ++ + Lvalue Iterator +Lvalue Iterator ++
++ + ++ + + + + If Iterator models +then filter_iterator models ++ Readable Iterator, Single Pass Iterator +Input Iterator ++ Readable Lvalue Iterator, Forward Traversal Iterator +Forward Iterator ++ + Writable Lvalue Iterator, Forward Traversal Iterator +Mutable Forward Iterator +filter_iterator<P1, X> is interoperable with filter_iterator<P2, Y> +if and only if X is interoperable with Y.
+
Returns: | a filter_iterator whose +predicate is a default constructed Predicate and +whose end is a default constructed Iterator. | +
---|
Effects: | Constructs a filter_iterator whose``m_pred``, m_iter, and m_end +members are a default constructed. | +
---|
Returns: | A filter_iterator at position x that filters according +to predicate f and that will not increment past end. | +
---|
Effects: | Constructs a filter_iterator where m_iter is either +the first position in the range [x,end) such that f(*m_iter) == true +or else``m_iter == end``. The member m_pred is constructed from +f and m_end from end. | +
---|
Returns: | A filter_iterator at position x that filters +according to a default constructed Predicate +and that will not increment past end. | +
---|
Effects: | Constructs a filter_iterator where m_iter is either +the first position in the range [x,end) such that m_pred(*m_iter) == true +or else``m_iter == end``. The member m_pred is default constructed. | +
---|
Returns: | A copy of iterator t. | +
---|
Effects: | Constructs a filter iterator whose members are copied from t. | +
---|
Returns: | A copy of the predicate object used to construct *this. | +
---|
Returns: | m_pred | +
---|
Returns: | The object end used to construct *this. | +
---|
Returns: | m_end | +
---|
At the end of the operations section, add:
+++reference operator*() const;
++
++ + + + + Returns: *m_iter +filter_iterator& operator++();
++
++ + + + Effects: Increments m_iter and then continues to +increment m_iter until either m_iter == m_end +or m_pred(*m_iter) == true. ++ + Returns: *this +
Change:
++class counting_iterator + : public iterator_adaptor< + counting_iterator<Incrementable, Access, Traversal, Difference> + , Incrementable + , Incrementable + , Access + , /* see details for traversal category */ + , Incrementable const& + , Incrementable const* + , /* distance = Difference or a signed integral type */> +{ + friend class iterator_core_access; + public: ++
to:
++class counting_iterator +{ + public: + typedef Incrementable value_type; + typedef const Incrementable& reference; + typedef const Incrementable* pointer; + typedef /* see below */ difference_type; + typedef /* see below */ iterator_category; ++
Change:
++private: + typename counting_iterator::reference dereference() const + { + return this->base_reference(); + } ++
to:
++ Incrementable const& base() const; + reference operator*() const; + counting_iterator& operator++(); + counting_iterator& operator--(); +private: + Incrementable m_inc; // exposition ++
After the synopsis, add:
+++If the Difference argument is use_default then +difference_type is an unspecified signed integral +type. Otherwise difference_type is Difference.
+iterator_category is determined according to the following +algorithm:
++if (CategoryOrTraversal is not use_default) + return CategoryOrTraversal +else if (numeric_limits<Incrementable>::is_specialized) + return iterator-category( + random_access_traversal_tag, Incrementable, const Incrementable&) +else + return iterator-category( + iterator_traversal<Incrementable>::type, + Incrementable, const Incrementable&) ++
The Incrementable type must be Default Constructible, Copy +Constructible, and Assignable. The default distance is +an implementation defined signed integegral type.
+The resulting counting_iterator models Readable Lvalue Iterator.
+After the requirements section, add:
+counting_iterator models
+++Specializations of counting_iterator model Readable Lvalue +Iterator. In addition, they model the concepts corresponding to the +iterator tags to which their iterator_category is convertible. +Also, if CategoryOrTraversal is not use_default then +counting_iterator models the concept corresponding to the iterator +tag CategoryOrTraversal. Otherwise, if +numeric_limits<Incrementable>::is_specialized, then +counting_iterator models Random Access Traversal Iterator. +Otherwise, counting_iterator models the same iterator traversal +concepts modeled by Incrementable.
+counting_iterator<X,C1,D1> is interoperable with +counting_iterator<Y,C2,D2> if and only if X is +interoperable with Y.
+
At the begining of the operations section, add:
++In addition to the operations required by the concepts modeled by +counting_iterator, counting_iterator provides the following +operations.+
Returns: | A default constructed instance of counting_iterator. | +
---|
Requires: | Incrementable is Default Constructible. | +
---|---|
Effects: | Default construct the member m_inc. | +
Returns: | An instance of counting_iterator that is a copy of rhs. | +
---|
Effects: | Construct member m_inc from rhs.m_inc. | +
---|
Returns: | An instance of counting_iterator with its base +object copy constructed from x. | +
---|
Effects: | Construct member m_inc from x. | +
---|
At the end of the operations section, add:
+++reference operator*() const;
++
++ + + + + Returns: m_inc +counting_iterator& operator++();
++
++ + + + Effects: ++m_inc ++ + Returns: *this +counting_iterator& operator--();
++
++ + + + Effects: --m_inc ++ + Returns: *this +Incrementable const& base() const;
++
++ + + + + Returns: m_inc +
Submitter: | Howard Hinnant | +
---|---|
Status: | New | +
c++std-lib-12585:
+Readable Iterator Requirements says:
++++
++ + ++ + + + + a->m +U& +pre: (*a).m is well-defined. Equivalent to (*a).m +
Do we mean to outlaw iterators with proxy references from meeting +the readable requirements?
+Would it be better for the requirements to read static_cast<T>(*a).m +instead of (*a).m ?
+Proposed resolution: | |
---|---|
NAD. | +|
Rationale: | We think you're misreading "pre:". +If (*a).m is not well defined, then the iterator is not +required to provide a->m. So a proxy iterator is not +required to provide a->m. +As an aside, it is possible for proxy iterators to +support ->, so changing the requirements to +read static_cast<T>(*a).m is interesting. +However, such a change to Readable Iterator would +mean that it no longer corresponds to the +input iterator requirements. So old iterators would not +necessarily conform to new iterator requirements. + |
+
Submitter: | Pete Becker | +
---|
c++std-lib-12635:
+counting_iterator takes an argument for its Traversal type, with a +default value of use_default. It is derived from an instance of +iterator_adaptor, where the argument passed for the Traversal type +is described as "/* see details for traversal category +*/". The details for counting_iterator describe constraints on +the Incrementable type imposed by various traversal +categories. There is no description of what the argument to +iterator_adaptor should be.
+Proposed resolution: | |
---|---|
We no longer inherit from iterator_adaptor. So instead, +we specify the iterator_category in terms of the Traversal type +(which is now called CategoryOrTraversal). Also the +requirements and models section was reorganized to +match these changes and to make more sense. | +
Submitter: | Pete Becker | +
---|
c++std-lib-12640:
++++The value_type of the Iterator template parameter should itself +be dereferenceable. The return type of the operator* for +the value_type must be the same type as the Reference template +parameter.+I'd say this a bit differently, to emphasize what's required: +iterator_traits<Iterator>::value_type must be dereferenceable. +The Reference template parameter must be the same type as +*iterator_traits<Iterator>::value_type().
++The Value template parameter will be the value_type for the +indirect_iterator, unless Value is const. If Value is const X, then +value_type will be non- const X.+Also non-volatile, right? In other words, if Value isn't use_default, it +just gets passed as the Value argument for iterator_adaptor.
+++The default for Value is:
++iterator_traits< iterator_traits<Iterator>::value_type >::value_type ++If the default is used for Value, then there must be a valid +specialization of iterator_traits for the value type of the +base iterator.
+The earlier requirement is that +iterator_traits<Iterator>::value_type must be +dereferenceable. Now it's being treated as an iterator. Is this +just a pun, or is iterator_traits<Iterator>::value_type +required to be some form of iterator? If it's the former we need +to find a different way to say it. If it's the latter we need to +say so.
+
Proposed resolution: | |
---|---|
Change: +++ to: ++++The expression *v, where v is an object of +iterator_traits<Iterator>::value_type, shall be valid +expression and convertible to reference. Iterator +shall model the traversal concept indicated by +iterator_category. Value, Reference, and +Difference shall be chosen so that value_type, +reference, and difference_type meet the requirements +indicated by iterator_category.+ |
+|
Rationale: | Not included above is the specification of the +value_type, reference, etc., members, which is handled by +the changes in 9.37x. | +
Submitter: | Pete Becker | +
---|
c++std-lib-12641:
++The reference type of transform_iterator is result_of< +UnaryFunction(iterator_traits<Iterator>::reference) +>::type. The value_type is +remove_cv<remove_reference<reference> >::type.+
These are the defaults, right? If the user supplies their own types +that's what gets passed to iterator_adaptor. And again, the +specification should be in terms of the specialization of +iterator_adaptor, and not in terms of the result:
+Reference argument to iterator_adaptor:
++if (Reference != use_default) + Reference +else + result_of< + UnaryFunction(iterator_traits<Iterator>::reference) + >::type ++
Value argument to iterator_adaptor:
++if (Value != use_default) + Value +else if (Reference != use_default) + remove_reference<reference>::type +else + remove_reference< + result_of< + UnaryFunction(iterator_traits<Iterator>::reference) + >::type + >::type ++
There's probably a better way to specify that last alternative, but +I've been at this too long, and it's all turning into a maze of +twisty passages, all alike.
+Proposed resolution: | |
---|---|
Replace: ++The reference type of transform_iterator is result_of< +UnaryFunction(iterator_traits<Iterator>::reference) +>::type. The value_type is +remove_cv<remove_reference<reference> >::type.+ with: +++ |
+
Submitter: | Pete Becker | +
---|
c++std-lib-12642:
+The paper says:
++template<class Predicate, class Iterator> +class filter_iterator + : public iterator_adaptor< + filter_iterator<Predicate, Iterator>, + Iterator, + use_default, + /* see details */ > ++
That comment covers the Access, Traversal, Reference, and Difference +arguments. The only specification for any of these in the details is:
++The access category of the filter_iterator will be the same as +the access category of Iterator.+
Needs more.
+Proposed resolution: | |
---|---|
Add to the synopsis: ++typedef iterator_traits<Iterator>::value_type value_type; +typedef iterator_traits<Iterator>::reference reference; +typedef iterator_traits<Iterator>::pointer pointer; +typedef iterator_traits<Iterator>::difference_type difference_type; +typedef /* see below */ iterator_category; ++ and add just after the synopsis: ++If Iterator models Readable Lvalue Iterator and Forward +Traversal Iterator then iterator_category is convertible +to std::forward_iterator_tag. Otherwise +iterator_category is convertible to +std::input_iterator_tag.+ |
+
Submitter: | Jeremy Siek | +
---|
We do not need to require that the function objects have the same +type, just that they be convertible.
+Proposed resolution: | |
---|---|
Change: ++template<class OtherIterator, class R2, class V2> +transform_iterator( + transform_iterator<UnaryFunction, OtherIterator, R2, V2> const& t + , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 // exposition +); ++ to: ++template<class F2, class I2, class R2, class V2> +transform_iterator( + transform_iterator<F2, I2, R2, V2> const& t + , typename enable_if_convertible<I2, Iterator>::type* = 0 // exposition only + , typename enable_if_convertible<F2, UnaryFunction>::type* = 0 // exposition only +); ++ |
+
Submitter: | Dave Abrahams | +
---|
indirect_iterator should be able to iterate over containers of +smart pointers, but the mechanism that allows it was left out of +the specification, even though it's present in the Boost +specification
+Proposed resolution: | |
---|---|
Add pointee and indirect_reference +to deal with this capability. +In [lib.iterator.helper.synopsis], add: ++template <class Dereferenceable> +struct pointee; + +template <class Dereferenceable> +struct indirect_reference; ++ After indirect_iterator's abstract, add: + |
+
Class template pointee
+ + + ++template <class Dereferenceable> +struct pointee +{ + typedef /* see below */ type; +}; ++
Requires: | For an object x of type Dereferenceable, *x +is well-formed. If ++x is ill-formed it shall neither be +ambiguous nor shall it violate access control, and +Dereferenceable::element_type shall be an accessible type. +Otherwise iterator_traits<Dereferenceable>::value_type shall +be well formed. [Note: These requirements need not apply to +explicit or partial specializations of pointee] | +
---|
type is determined according to the following algorithm, where +x is an object of type Dereferenceable:
++if ( ++x is ill-formed ) +{ + return ``Dereferenceable::element_type`` +} +else if (``*x`` is a mutable reference to + std::iterator_traits<Dereferenceable>::value_type) +{ + return iterator_traits<Dereferenceable>::value_type +} +else +{ + return iterator_traits<Dereferenceable>::value_type const +} ++
Class template indirect_reference
+ + + ++template <class Dereferenceable> +struct indirect_reference +{ + typedef /* see below */ type; +}; ++
Requires: | For an object x of type Dereferenceable, *x +is well-formed. If ++x is ill-formed it shall neither be +ambiguous nor shall it violate access control, and +pointee<Dereferenceable>::type& shall be well-formed. +Otherwise iterator_traits<Dereferenceable>::reference shall +be well formed. [Note: These requirements need not apply to +explicit or partial specializations of indirect_reference] | +
---|
type is determined according to the following algorithm, where +x is an object of type Dereferenceable:
++if ( ++x is ill-formed ) + return ``pointee<Dereferenceable>::type&`` +else + std::iterator_traits<Dereferenceable>::reference ++
See proposed resolution to Issue 9.37x for more changes related to +this issue.
+Submitter: | Dave Abrahams | +
---|
"because specification helps to highlight that the Reference +template parameter may not always be identical to the iterator's +reference type, and will keep users making mistakes based on +that assumption."
+Proposed resolution: | |
---|---|
add "from" before "making" + |
+
mention of obsolete projection_iterator
++++
++ + + + Proposed Resolution: + + From n1530, in the Specialized Adaptors section, remove:
++projection_iterator, which is similar to transform_iterator +except that when dereferenced it returns a reference instead of +a value.++ + Rationale: This iterator was in the original boost library, but the new +iterator concepts allowed this iterator to be +folded into transform_iterator. +
Submitter: | Dave Abrahams | +
---|
We've had some real-life reports that iterators that use +iterator_adaptor's base() function can be inefficient +when the Base iterator is expensive to copy. Iterators, of +all things, should be efficient.
+Proposed resolution: | |
---|---|
In [lib.iterator.adaptor] +Change: ++Base base() const; ++ to: ++Base const& base() const; ++ twice (once in the synopsis and once in the public +operations section). + |
+
Submitter: | Jeremy Siek | +
---|
We want Forward Traversal Iterator plus Readable Lvalue Iterator to +match the old Foward Iterator requirements, so we need Forward +Traversal Iterator to include Default Constructible.
+Proposed resolution: | |||||||
---|---|---|---|---|---|---|---|
Change: +++ to: +++ |
+
A general cleanup and simplification of the requirements and +description of type members for iterator_facade.
+The user is only allowed to add const as a qualifier.
+We use to have an unspecified type for pointer, to match the +return type of operator->, but there's no real reason to make them +match, so we just use the simpler Value* for pointer.
+Change:
++typedef /* see description of operator-> */ pointer;+
The nested ::value_type type will be the same as +remove_cv<Value>::type, so the Value parameter must be +an (optionally const-qualified) non-reference type.
+The nested ::reference will be the same as the Reference +parameter; it must be a suitable reference type for the resulting +iterator. The default for the Reference parameter is +Value&.
+Change:
+++In the table below, X is the derived iterator type, a is an +object of type X, b and c are objects of type const X, +n is an object of X::difference_type, y is a constant +object of a single pass iterator type interoperable with X, and z +is a constant object of a random access traversal iterator type +interoperable with X.
++
++ + ++ + + + + + + Expression +Return Type +Assertion/Note +Required to implement +Iterator Concept(s) ++ c.dereference() +X::reference ++ Readable Iterator, Writable +Iterator ++ c.equal(b) +convertible to bool +true iff b and c are +equivalent. +Single Pass Iterator ++ c.equal(y) +convertible to bool +true iff c and y refer to the +same position. Implements c == y +and c != y. +Single Pass Iterator ++ a.advance(n) +unused ++ Random Access Traversal +Iterator ++ a.increment() +unused ++ Incrementable Iterator ++ a.decrement() +unused ++ Bidirectional Traversal +Iterator ++ c.distance_to(b) +convertible to +X::difference_type +equivalent to distance(c, b) +Random Access Traversal +Iterator ++ + c.distance_to(z) +convertible to +X::difference_type +equivalent to distance(c, z). +Implements c - z, c < z, c +<= z, c > z, and c >= c. +Random Access Traversal +Iterator +
to:
+++In the table below, F is iterator_facade<X,V,C,R,D>, a is an +object of type X, b and c are objects of type const X, +n is an object of F::difference_type, y is a constant +object of a single pass iterator type interoperable with X, and z +is a constant object of a random access traversal iterator type +interoperable with X.
+iterator_facade Core Operations
++
++ + ++ + + + + + + Expression +Return Type +Assertion/Note +Used to implement Iterator +Concept(s) ++ c.dereference() +F::reference ++ Readable Iterator, Writable +Iterator ++ c.equal(y) +convertible to bool +true iff c and y +refer to the same +position. +Single Pass Iterator ++ a.increment() +unused ++ Incrementable Iterator ++ a.decrement() +unused ++ Bidirectional Traversal +Iterator ++ a.advance(n) +unused ++ Random Access Traversal +Iterator ++ + c.distance_to(z) +convertible to +F::difference_type +equivalent to +distance(c, X(z)). +Random Access Traversal +Iterator +
+template < + class Derived + , class Base + , class Value = use_default + , class CategoryOrTraversal = use_default + , class Reference = use_default + , class Difference = use_default +> +class iterator_adaptor + : public iterator_facade<Derived, V, C, R, D> // see details +{ + friend class iterator_core_access; + public: + iterator_adaptor(); + explicit iterator_adaptor(Base iter); + Base base() const; + protected: + Base const& base_reference() const; + Base& base_reference(); + private: // Core iterator interface for iterator_facade. + typename iterator_adaptor::reference dereference() const; + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; + + void advance(typename iterator_adaptor::difference_type n); + void increment(); + void decrement(); + + template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D + > + typename iterator_adaptor::difference_type distance_to( + iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; + + private: + Base m_iterator; // exposition only +}; ++
The V, C, R, and D parameters of the iterator_facade +used as a base class in the summary of iterator_adaptor +above are defined as follows:
++V = if (Value is use_default) + return iterator_traits<Base>::value_type + else + return Value + +C = if (CategoryOrTraversal is use_default) + return iterator_traversal<Base>::type + else + return CategoryOrTraversal + +R = if (Reference is use_default) + if (Value is use_default) + return iterator_traits<Base>::reference + else + return Value& + else + return Reference + +D = if (Difference is use_default) + return iterator_traits<Base>::difference_type + else + return Difference ++
The Derived template parameter must be a publicly derived from +iterator_adaptor. In order for Derived to model the +iterator concepts corresponding to +iterator_traits<Derived>::iterator_category, the expressions +involving m_iterator in the specifications of those private +member functions of iterator_adaptor that may be called by +iterator_facade<Derived, V, C, R, D> +in evaluating any valid expression involving Derived +in those concepts' requirements.
+iterator_adaptor();
+Requires: | The Base type must be Default Constructible. | +
---|---|
Returns: | An instance of iterator_adaptor with +m_iterator default constructed. | +
explicit iterator_adaptor(Base iter);
+Returns: | An instance of iterator_adaptor with +m_iterator copy constructed from iter. | +
---|
Base base() const;
+Returns: | m_iterator | +
---|
Base const& base_reference() const;
+Returns: | A const reference to m_iterator. | +
---|
Base& base_reference();
+Returns: | A non-const reference to m_iterator. | +
---|
typename iterator_adaptor::reference dereference() const;
+Returns: | *m_iterator | +
---|
+template < +class OtherDerived, class OtherIterator, class V, class C, class R, class D +> +bool equal(iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& x) const; ++
Returns: | m_iterator == x.base() | +
---|
void advance(typename iterator_adaptor::difference_type n);
+Effects: | m_iterator += n; | +
---|
void increment();
+Effects: | ++m_iterator; | +
---|
void decrement();
+Effects: | --m_iterator; | +
---|
+template < + class OtherDerived, class OtherIterator, class V, class C, class R, class D +> +typename iterator_adaptor::difference_type distance_to( + iterator_adaptor<OtherDerived, OtherIterator, V, C, R, D> const& y) const; ++
Returns: | y.base() - m_iterator | +
---|
Author: | +David Abrahams, Jeremy Siek, Thomas Witt |
---|---|
Contact: | +dave@boost-consulting.com, jsiek@osl.iu.edu, witt@styleadvisor.com |
Organization: | +Boost Consulting, Indiana University Open Systems +Lab, Zephyr Associates, Inc. |
Date: | +2004-01-27 |
Copyright: | +Copyright David Abrahams, Jeremy Siek, and Thomas Witt 2004. All rights reserved |
abstract: | The iterator concept checking classes provide a mechanism for +a template to report better error messages when a user instantiates +the template with a type that does not meet the requirements of +the template. | +
---|
For an introduction to using concept checking classes, see +the documentation for the boost::concept_check library.
++namespace boost_concepts { + + // Iterator Access Concepts + + template <typename Iterator> + class ReadableIteratorConcept; + + template < + typename Iterator + , typename ValueType = std::iterator_traits<Iterator>::value_type + > + class WritableIteratorConcept; + + template <typename Iterator> + class SwappableIteratorConcept; + + template <typename Iterator> + class LvalueIteratorConcept; + + // Iterator Traversal Concepts + + template <typename Iterator> + class IncrementableIteratorConcept; + + template <typename Iterator> + class SinglePassIteratorConcept; + + template <typename Iterator> + class ForwardTraversalConcept; + + template <typename Iterator> + class BidirectionalTraversalConcept; + + template <typename Iterator> + class RandomAccessTraversalConcept; + + // Interoperability + + template <typename Iterator, typename ConstIterator> + class InteroperableIteratorConcept; + +} ++
+template <class Predicate, class Iterator> +filter_iterator<Predicate,Iterator> +make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()); ++
Returns: | An instance of filter_iterator<Predicate,Iterator> +where m_iter is either the first position in the range [x,end) such that +f(*this->base()) == true or else m_iter == end. +The member m_pred is constructed from f and m_end from end. | +
---|
+template <class Predicate, class Iterator> +filter_iterator<Predicate,Iterator> +make_filter_iterator(Iterator x, Iterator end = Iterator()); ++
Returns: | An instance of filter_iterator<Predicate,Iterator> +where m_iter is either the first position in the range [x,end) +such that f(*this->base()) == true, where f is a default +constructed Predicate, or else m_iter == end. +The member m_pred is default constructed and m_end +is constructed from end. | +
---|
Author: | David Abrahams and Jeremy Siek | +
---|---|
Contact: | dave@boost-consulting.com, jsiek@osl.iu.edu | +
Organization: | Boost Consulting, Indiana University Bloomington | +
date: | $Date$ | +
Copyright: | Copyright David Abrahams, Jeremy Siek 2003. Use, modification and +distribution is subject to the Boost Software License, +Version 1.0. (See accompanying file LICENSE_1_0.txt or copy +at http://www.boost.org/LICENSE_1_0.txt) | +
The new iterator categories are intended to correspond to the old +iterator categories, as specified in a diagram in N1550. For example, +an iterator categorized as a mutable Forward Iterator under the old +scheme is now a Writable, Lvalue, and Foward Traversal iterator. +However, there is a problem with this correspondance, the new iterator +categories place requirements on the iterator_traits<X>::reference +type whereas the standard iterator requirements say nothing about the +reference type . In particular, the new Readable Iterator +requirements say that the return type of *a must be +iterator_traits<X>::reference and the Lvalue Iterator requirements +says that iterator_traits<X>::reference must be T& or const +T&.
+Change the standard requirements to match the requirements of the new +iterators. (more details to come)
+The lack of specification in the standard of the reference type is +certainly a defect. Without specification, it is entirely useless in a +generic function. The current practice in the community is generally +to assume there are requirements on the reference type, such as +those proposed in the new iterator categories.
+There is some danger in adding requirements to existing concepts. +This will mean that some existing iterator types will no longer meet +the iterator requirements. However, we feel that the impact of this is +small enough to warrant going ahead with this change.
+An alternative solution would be to leave the standard requirements as +is, and to remove the requirements for the reference type in the +new iterator concepts. We are not in favor of this approach because it +extends what we see as a defect further into the future.
+