1. Changes
1.1. Revision 1
- 
     Refine the impact on the standard 
- 
     Mention ITER_CONCEPT 
- 
     Remove the idea the ranges :: copy 
- 
     Replace Cpp17Iterator by LegacyIterator to reflect the standard 
- 
     Remove the very wrong idea of having view return begin () 
- 
     Fix some confusing phrasing 
2. Introduction
Non-forward Input iterators and output iterators, also known as "Single-pass iterators" are semantically move-only. The standard states:
Note: For input iterators, a == b does not imply ++a == ++b (Equality does not guarantee the substitution property or referential transparency.) Algorithms on input iterators should never attempt to pass through the same iterator twice. They should be single pass algorithms.
This means that once an iterator is copied, only one of the copies can be read-from if either one is incremented, which make the usefulness of such object questionable. Deferencing multiple copies of a single pass iterator often exposes undefined or invalid behavior if either one is incremented: the following example exposes Undefined behavior:
auto other = some_input_iterator ; std :: cout << * ( ++ other ) << * some_input_iterator << '\n' ; 
It would, therefore, make sense that classes satisfying the 
Alas, Single-pass iterators and many classes satisfying its requirements predate C++11, they do therefore have move only semantic with copy syntax.
In that regard, they are similar to 
3. Terminology
This paper redefines the requirements of some concepts as specified in the Working Draft In the rest of this paper
- 
     InputIterator InputIterator 
- 
     Cpp20InputIterator InputIterator 
- 
     OutputIterator OutputIterator 
- 
     OutputIterator OutputIterator 
4. Scope
This paper proposes changes targeting C++20. Because the modifications proposed here changes some requirements and concepts introduced by Ranges, the authors strongly suggest they are considered for the inclusion in the same version of the standard. Indeed, Concepts introduced by ranges gives us a unique opportunity to make the modifications proposed, as they might, in some cases, break code, if introduced after the publication of C++20.
4.1. Non-Goal
As a large amount of code depends on the Input/Output iterators requirements as specified by C++17, this paper does not propose any modifications to the 
While the ability to use move-only iterators with the algorithms defined in the 
In practice, that means that types satisfying the 
Inversely, types satisfying the 
Because it hardly makes sense to copy an Input Iterator (more on that later), it would be possible to add support for move-only iterators to the 
Furthermore, while we propose to add support for movable non-forward iterators, the proposed design does not preclude, in any way, the existance of copyable non-forward iterators.
5. Motivation
5.1. Move-only state
It may be desirable for an iterator to hold a move-only object, becoming itself move-only, which is not possible with iterators modeling LegacyIterator.
A real-world example of such iterator is described in [P0902R0].
While syntactically copyable in the current design, a 
5.2. Implicitly destructive operations
Reading from an input sequence is a destructive operation. But that destruction is reflected nowhere in the API.
Less experienced developers may not be aware of the destructive / single-pass nature of non-forward Iterators
By making 
6. What is a move-only iterator?
Unlike [P0902R0], we do not propose to introduce a new iterator category.
A move-only Iterator is a non-forward iterator (either input or output depending on whether is it writable).
This means that a move-only iterator has almost the same semantic requirements as an 
Therefore, this paper does not propose to introduce a new iterator category, new named-requirement, concept name or iterator tag.
Furthermore, there is no 
7. A Holistic Approach to Iterators
While the first part of this paper focuses on making move-only iterators possible, as a means to get some code to compile, it is important to take a step back and to think about what movability means for Iterators, from first principles.
An iterator denotes a position into a sequence of elements (whether that sequence maps to memory or not is, for our purpose, irrelevant).
A most basic iterator can be incremented, which means it can move to the next position in the sequence. An iterator does not own the sequence iterated over (there are exceptions, ie: generators), which means the salient property of an iterator is its position in that sequence.
Iterators categories then represent the way an iterator can move along that sequence.
- 
     Input and FordwardIterator: sequentially, one direction 
- 
     BidirectionalIterator: sequentially, both directions 
- 
     RandomAccess: both directions in O(1) 
ContiguousIterator is an optimization of RandomAccessIterator specific to the C++ memory model that further, constrain the underlying sequence to be laid out contiguously in memory.
Stepanov theorized an additional category, "Index iterator", which has O(1) access but in a single direction.
Further work was made on iterator categories, notably the Boost.Iterator library
focused on separating traversal (how the iterator moves along the sequence) from
access (whether dereferencing an iterator allows the pointed element to be read, written or both).
While a very interesting concept, it falls outside the scope of this paper.
Just keep in mind that everything that applies to non-forward 
However, focusing on traversal, the set of iterators categories is actually
rather closed, there are only so many ways a sequence can be traversed. An
important point of Stepanov design is that each category is a refinement of the preceding one. 
So, what separates 
The standard defines the "multi pass" guarantee by stating:
a == b implies ++a == ++b
Given X is a pointer type or the expression (void)++X(a), a is equivalent to the expression a.
In other words:
Two identical objects to which is applied the same transformation are identical.
Copying a 
Which bring us to 
//Given an InputIterator a auto b = a ; a ++ ; b ; // is invalid. 
However, remember that the sole salient property of an iterator is its distance to the start of the sequence.
Incrementing an iterator only mutates that property (again, conceptually, independently of implementation).
And the only operation that mutates that property is the increment operation (which Stepanov calls 
This implies that as a non-forward iterator moves from one element of the sequence to the next, that element is destroyed.
All of this is well known and is basically rephrasing "Input iterators are single pass".
An important point to make is that how an iterator can traverse a sequence is derived from the nature of the sequence rather than from the iterator itself. The point could be made that there is no such thing as an "Input iterator" Or a "Forward Iterator" because what we really mean is "Iterator over an Input Sequence" or "Iterator over a Forward Sequence".
This is saying that, to be able to reason properly about iterators and traversal, we must assume that the iterator type associated with a sequence is the most specialized possible for that sequence.
The problem is, of course, that we do not have, in the general case, a more meaningful way to express the traversability of a sequence than by defining what type of iterator is used to iterate over it.
It is then the responsibility of the developer providing the sequence to define the most appropriate -- the most specialized -- iterator category for that sequence.
In practice, because 
But then, is there a set of operations and semantic requirements, translating to actual C++ syntax, that could allow for
InputIterator to be easily distinguished from each other?
Can we avoid requiring a tag system?
Is there a defining operation that distinguishes 
In fact, there is. We established that 
This model, however, deviates slightly from Stepanov’s work and 
Elements Of Programming has the notion of 
For 
Like a pointer, 
InputIterator i = /*...*/ * i //ok auto a = i //ok * i //ok i ++ ; // a now invalid 
This design accurately models the nature of iterators. Because an iterator represents a position in a sequence, it is natural that multiple iterators could point to the same position. After one copy is incremented, in Stepanov’s model, other copies are in a partially formed state and cannot be used (but they can be assigned to, or destroyed).
Let’s consider the case where we move from an iterator instead of copying it
InputIterator i = /*...*/ * i //ok auto a = move ( i ); //ok * i ; //invalid a ++ ; //ok i ++ ; //invalid 
Moving from an iterator invalidates it early, albeit artificially. As per standard, the moved-from iterator is in a valid, but unspecified state, and cannot be used (but can be assigned to, or destroyed). Notice the similarity between "a valid, but unspecified state" and "a partially formed state".
The difference is slim. Notably, both models are equally expressive. References can be used, should multiple names be necessary. In Stepanov’s model iterators are made invalid by the natural mutation of the sequence upon increment rather than by artificially preventing multiple copies.
The second model in which the iterator is moved from, the one we think should be the default way to handle non-forward iterators, is however a much better fit for the C++ model, and offers much stronger guarantees to both the human developer as well as static analysis tools.
In the "increment invalidates" model, objects are spiritually moved-from at a distance, which neither the theory of special relativity nor the C++ memory, model are equipped to handle. This makes it hard for tools to detect invalid uses - although it might become possible with better tools (See Herb Sutter’s CppCon2018 talk). But most concerning, there is no way for a developer to know that the iterators are entangled.
auto i = troubles . begin (); auto schrodingers_iterator = i ; i ++ ; auto nasal_demon = * schrodingers_iterator ; 
The code above might be perfectly fine.
Indeed whether it is well defined or not depends on whether the iterator return by 
Even worse, should the type of 
Moving non-forward iterators, therefore, better expresses intent, is safer and less surprising.
Move-only non-forward Iterators also express the destructive nature of incrementation and give a better sense of the difference between 
7.1. An Holistic Approach to Iterator Tags and Iterator Concepts
Missing the notion of movability pre-c++11 and lacking concepts, 
- 
     Have semantic requirements not expressed through syntax and therefore not enforceable at compile time 
- 
     Need syntax to artificially subscribe to the correct, most refined concept 
Of course, it is not always possible to express all of a type’s semantic requirements through syntax, and in some cases, tags are an unfortunate necessity. However, they should be the mechanism of last recourse, and whenever possible, the semantic requirements should be reflected in the syntax. The idea is that hidden requirements not expressed as code lead to easier-to-misuse types, which inevitably translates to runtime bugs. Ultimately, requirements that can neither be checked at compile time (concepts) or runtime (contracts) are bound to be ignored. Rooted in the belief that not all birds quack like a duck, this proposal leverages meaningful syntactic requirements to increase the type safety of the iterator taxonomy.
In the case of iterators, all requirements of all iterators categories can be expressed syntactically:
template < class I > concept bool InputIterator = Readable < I > && Iterator < I > ; template < class I > concept bool ForwardIterator = InputIterator < I > && Copyable < I > && EqualityComparable < I > ; template < class I > concept bool BidirectionalIterator = ForwardIterator < I > && Decrementable < I > ; template < class I > concept bool RandomAccessIterator = BidirectionalIterator < I > && RandomAccessIncrementable < I > ; template < class I > concept bool ContiguousIterator = RandomAccessIterator < I > && ConvertibleTo < I , std :: add_const_t < iter_value_t < I >>*> 
This is of course simplified but shows that each iterator category subsumes the last and adds a single, cohesive set of requirement enforceable at compile-time. In this design, there is no risk of a type satisfying the wrong concept because of a poorly chosen tag.
7.1.1. Tags as an opt-in opt-out mechanism
Iterators concepts already support semantic-only checking of iterator requirements for types that do not define either iterator_category or iterator concept. Currently, this machinery will identify categories from ForwardIterator to RandomAccessIterator. With this proposal, non-copyable tagless types that otherwise meet the requirements of InputIterator be correctly identified as non-forward InputIterator, which is always the correct assumption. Copyable tagless iterators will remain categorized as ForwardIterator by that machinery.
8. Q/A
8.1. Non-regular iterators, really?
This proposal advocates for Non-Regular Iterators, and weakens 
However, non-regular types are easier to reason about than types that just pretend to be regular.
Because 
8.2. What about Equality of Input Iterators?
A first, misguided, version of this paper attempted to prevent comparability of types meeting the 
However, preventing 
Early feedback suggested a desire to be able to compare non-forward iterators. Consider the following:
auto a = stream . begin (); auto b = stream . begin (); ... if ( a == b ) { } 
This code will inevitably lead to suffering at some point. However, we cannot prevent people from constructing multiple non-forward iterators, and these iterators will compare equal until one of them invalidate the other.
Two non-forward iterators compare equal if-and-only-if they point to the same position of the same sequence (and only one such position can be referred to at any given time).
Allowing 
8.3. But... Moved-from objects are still objects!
Sure, moving-from leaves a trail of objects in an unspecified state.
However, it is much more easy for tools and humans alike to understand that moved-from objects should
not be used, and in fact, all majors compilers can warn about these patterns.
We think that for the case at hand, focusing on the proper handling of values -- as opposed to objects —
8.4. Does iterators default-constructability needs revisiting?
Default-constructability of iterator seems to have been added, removed and added back to the Ranges TS and the One Ranges Proposal several times. To the best of my knowledge, this was done for the sake of Semiregularity. Given that this proposal strikes semi-regularity, should this question be revisited?
The authors want to point out that default-constructed iterators are almost never in a specified
state and are almost always unsafe to use.
Moreover, DefaultConstructible is not a requirement of any algorithm using ranges and ultimately, we think enforcing
DefaultConstructibility weakens the better 
8.5. What about [P0902R0]?
Andrew Hunter’s "Move-only iterators" paper proposes a design to introduce Move-Only iterators in the taxonomy of 
However, if LEWG feels strongly about a solution compatible with existing algorithms it would be possible
to relax the requirements of concerned algorithms to accept move-only iterators. along with the introduction of a new 
Such algorithms would then be compatible with types satisfying 
If proven with enough confidence that requirements of existing algorithms in the 
So while there would definitively be value in supporting move-only iterators everywhere it makes sense, and the potential for breakage is relatively low, we do not propose it for lack of visibility on the consequences of such changes.
8.6. Why do you want to take my Copyable InputIterators away from me, I like them?!
We do not propose anything of the sort. But, we propose that
- 
     Any InputIterator Copyable ForwardIterator 
- 
     It remains possible to opt-out of that behavior by defining iterator_concept input_iterator_tag 
| Non-copyable Iterator | Copyable Iterator | Copyable Iterator with a tag | 
|---|---|---|
| 
 | 
 | 
 | 
| 
 | 
 | 
 | 
8.7. Will this break existing code ?!
We want to reiterate(!) that all the changes proposed in this paper are only applicable to concepts, types, and requirements that were added to the standard by the Ranges proposal. They do not, in any way, impact code depending on types, requirements or algorithms as defined by the C++17 standard
8.8. Won’t that implicit categorization lead to miss-categorization?
The only valid use cases for 
This proposal is also a teaching opportunity because the nature of 
8.9. Post Increment on non-copyable iterators
Post-incrementing move-only iterators would obviously be incorrect. However, a satisfying solution was offered by [P0541R1].
9. Questions for LEWG
- 
     Does LEWG want to support non-copyable iterators in the ranges 
- 
     Does LEWG agree that non-copyable iterators are always non-forward iterators and do not constitute a new category (ie: no new tag should be introduced)? 
- 
     Does LEWG agree that, in the absence of an explicit tag, a non-copyable iterator that otherwise meets the requirement of InputIterator OutputIterator 
- 
     Does LEWG agree that, in the absence of an explicit tag, a copyable iterator that otherwise meets the requirement of ForwardIterator 
- 
     Does LEWG want to recommend that future non-forward iterators considered for inclusion in the standard should not be copyable? 
- 
     Does LEWG want to revisit the default constructability of iterators given Regular Iterator 
- 
     Does LEWG want to recognize RandomAccessIterator pointer ContiguousIterator 
10. List of proposed changes
Because the ranges-related proposals are still in flux and will require merging multiple documents, we do not provide wording at this time. However, a number of concepts need to be modified in order to allow for iterators that are only movable. This is a departure from the current Standard Concepts Requirements - which itself is grounded in Stepanov work - in which all iterator categories are Regular - or Semi-Regular, which implies copyability.
Note that "ForwardIterator" is defined in terms of its copyability, and so it shall remain regular.
The Copyability, and therefore Regularity of Iterator is therefore moved a few levels down from 
10.1. Changes to <iterator>
10.1.1. WeaklyIncrementable
template < class I > concept WeaklyIncrementable = Movable < I > && requires ( I i ) { typename iter_difference_t < I > ; requires SignedIntegral < iter_difference_t < I >> ; { ++ i } -> Same < I >& ; // not required to be equality-preserving i ++ ; // not required to be equality-preserving }; 
10.1.2. Iterator
10.1.3. InputIterator
The 
Tagless move-only input iterators will also be correctly identified by the 
10.1.4. OutputIterator
The 
10.1.5. ContiguousIterator
template < class I , class T > concept ContiguousIterator = ContiguousIterator = RandomAccessIterator < I > && std :: is_lvalue_reference < iter_reference_t < I >>:: value && Same < iter_value_t < I > , __uncvref < iter_reference_t < I >>> && ( DerivedFrom < ITER_CONCEPT ( I ), contiguous_iterator_tag > || ConvertibleTo < I , std :: add_const_t < iter_value_t < I >>*> ); 
Requiring a conversion operator to 
10.2. Changes to <ranges>
10.2.1. Views
Unlike R0, this paper does not propose to remove the SemiRegular requirement from view. View over non-forward ranges should not hold or cache the result of calling begin()
10.2.2. Inserters
Because the 
It is, therefore, necessary to provide suitable inserters modeling 
10.2.2.1. back_insert_iterator
namespace std :: ranges { template < class Container > class back_insert_iterator : public std :: back_insert_iterator < Container > { public : using std :: back_insert_iterator < Container >:: back_insert_iterator ; back_insert_iterator ( const back_insert_iterator & other ) = delete ; back_insert_iterator ( back_insert_iterator && other ) }; template < class Container > back_insert_iterator < Container > back_inserter ( Container & x ); } 
10.2.2.2. front_insert_iterator
namespace std :: ranges { template < class Container > class front_insert_iterator : public std :: front_insert_iterator < Container > { public : using std :: front_insert_iterator < Container >:: front_insert_iterator ; front_insert_iterator ( const front_insert_iterator & other ) = delete ; front_insert_iterator ( front_insert_iterator && other ); }; template < class Container > front_insert_iterator < Container > front_inserter ( Container & x ); } 
10.2.2.3. insert_iterator
namespace std :: ranges { template < class Container > class insert_iterator : public std :: insert_iterator < Container > { public : using std :: insert_iterator < Container >:: insert_iterator ; insert_iterator ( const insert_iterator & other ) = delete ; insert_iterator ( insert_iterator && other ); }; template < class Container > insert_iterator < Container > inserter ( Container & x , typename Container :: iterator i ); } 
10.2.3. counted_iterator
- 
     counted_iterator 
- 
     counted_iterator :: base () 
10.2.4. move_iterator
- 
     move_iterator 
- 
     move_iterator :: base () 
10.3. Changes to <algorithm>
There should be no wording change to algorithms. However, implementers would have to never copy non-forward iterators within the implementation of C++20 ranges based and ranges:: algorithms.
11. Impact on other proposals
11.1. View proposals
We suggest that the various proposals introducing new non-forward views should have iterators that are neither copyable nor equally comparable.
A candidate for such change would be [P1035R1]'s 
11.2. Iterator facade
[P0186R0] describes a system for an iterator facade. The changes proposed make defining iterators easier but we think there is still value in an iterator facade. To accommodate and honor the changes proposed here, we suggest that:
- 
     Cursor 
- 
     An iterator constructed from a move-only Cursor InputIterator OutputIterator write 
- 
     An iterator facade constructed from a Copyable cursor with an equal ( const cursor & ) ForwardIterator single_pass = true
- 
     cursor :: Forward Semi - regularC > && ! C :: single_pass 
- 
     cursor :: Contiguous ConvertibleTo < value_type_t < C >* , C > || C :: contiguous ; 
12. Implementation experience
We validated the design in cmstl2.
However, cmcstl2 deviates from the Working Draft as it doesn’t have the same Deep Integration system and therefore lacks the 
12.1. Acknowledgments
The authors like to thank Connor Waters, Tony Van Eerd, Eric Niebler, Casey Carter, Christopher Di Bella, Sean Parent and Arthur O’Dwyer who gave tremendously helpful feedbacks during the writing of this paper.