7

How does one define forward-output-iterators in C++11 in a canonical way?

According to the standard a forward_iterator is only a input_iterator. So the corresponding forward_iterator_tag only extends input_iterator_tag. If we are using std::iterator to define our iterators, what tag do we use for a forward-output-iterator?

Is it canonical to define a private tag that extends both forward_iterator_tag and output_iterator_tag or is there a better solution?

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
MFH
  • 1,664
  • 3
  • 18
  • 38

1 Answers1

6

The canonical thing to do is to inherit from std::iterator<std::forward_iterator_tag, T> only. Iterators have only one category.

The standard has no algorithms (or other uses) for an output iterator that is also a forward iterator. All uses of output iterators in the standard require only single-pass.

Instead, the standard has the idea of mutable vs. immutable iterators of categories forward/bidi/randomaccess. All the algorithms that need to write through iterators, and that require better than single-pass, also read through the same iterators they write through. This is std::remove, std::sort and other mutating algorithms.

The difference between mutable and immutable iterators is not detected by iterator tag, it's determined by whether the assignment expressions are well-formed. So for example if you pass an iterator to std::sort that's immutable, then the algorithm won't compile anyway, so there's generally no need for an input iterator to also be tagged with output_iterator_tag. All algorithms that require an OutputIterator will Just Work with a mutable ForwardIterator, again there is no need for it to be tagged with output_iterator_tag.

If you have different needs from those of the standard algorithms then I can't immediately think of a reason that your proposal won't work for your iterators. But it won't detect mutable standard iterators. For example std::deque<int>::iterator and int* have iterator category random_access_iterator_tag, not your private tag and not anything to do with output_iterator_tag. So you would probably be better off defining your own traits class rather than hoping to adapt the existing iterator_traits::iterator_category to provide the information you want.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • Thanks! That cleared things up quite much. In the end this implies that immutable iterators return const references/copies of the pointed to element to prevent assignment via the returned reference, right? – MFH Dec 28 '12 at 19:28
  • 1
    @MFH: that's right. Immutable iterators over containers return `const T&` (I haven't checked whether that's actually required, or if they're allowed to return proxies instead). Other immutable iterators can return anything convertible to `T`. – Steve Jessop Dec 29 '12 at 14:04
  • @SteveJessop: this is probably overdue for an updated, since use of `std::iterator` has been deprecated for a while now. – Jerry Coffin Nov 07 '22 at 17:46
  • @JerryCoffin: go for it :-) . I'm not tracking C++ any more so I'd have to look up the new correct answer. – Steve Jessop Nov 23 '22 at 12:24