
David Abrahams wrote:
I see that std::input_iterator requirements say that after ++r any copies of the previous value of r are no longer required to be dereferencable.
Right. That rules out your scenario of keeping old copies of the iterator around and derferencing them later.
True. I did not see that clause until yesterday.
New iterators requirents are silent on this. Is this intentional?
Probably not. However, if the standard doesn't explicitly guarantee iterator stability, you can't count on it. That said, a note would probably be good to add.
Okay. BTW, what guarantees that ++r does not invalidate any copies for forward/bidirectional/random iterator?
If single pass iterator requirements ^^... - would add the same note about ++r making iterators dereferencable "non-"----------^ Probably a good idea.
- retain the same requirements for operator++(int)
Really you mean requirements on the expression "*r++", I think.
No, on operator++(int)
...then what?
The result of r++ is not required even to be dereferencable
Not required by which concept?
By nothing I could find in new iterator requirements. Requirements on operator++(int) say: { X tmp = r; ++r; return tmp; } operator++ is allowed to invalidate 'tmp', and nothing explicitly requires return value from operator++(int) to be dereferencable.
The solutions I see are:
1) require that ++r does not makes any copies dereferencable, or
I think you mean "not require that any copies are dereferencable after "++r"?
Nope, I meant what written. If ++r is required to keep the copies deferencable then *r++ will be guaranteed to work. OTOH, this would require storing value in iterator which as you say is not indented by current input_iterator.
2) allow returning proxy from operator++(int)
That doesn't allow all readable single-pass iterators to be input iterators. I'm against it.
It's possible to require that return value from operator++(int) is some type with operator* and application of operator* returns the same value as the *it before incrementing.
What would the proxy do, anyway?
Here's commented out code in filesystem lib: struct path_proxy // allows *r++ to work, as required by 24.1.1 { path pv; explicit path_proxy( const path & p ) : pv(p) {} path operator*() const { return pv; } }; path_proxy operator++(int) { path_proxy pp( m_deref() ); ++*this; return pp; }
3) require that result of r++ is dereferencable and is equivivalent to the dereferencing of the previous value of 'r'.
I think we need want 1&3.
Will 3) require extra storage in iterator? Now, transform_iterator can store only wrapped iterator and a functor. If 3) is required it should additionally store either value, or a flag telling there's a undereferenced copy (as you've suggested). Besides, In the second case it should be stated that return of r++ is dereferencable untill you call operator*() or operator++() on original iterator.
The variant 2) would be most convenient for directory_iterator...
Yeah, but it would break interoperability with old algorithms.
Why? Input iterator requirements only say that *r++ should return T. They don't say anything about type of r++. - Volodya Yeah, but it would break interoperability with old algorithms.