boost::iterator_facade problem with postfix increment proxy
I want to implement my own iterator as single pass traversal with reference type value& (a genuine reference). My problem is, that the iterator facade concludes from the single pass traversal, that this is an input/output iterator and those are generelly subject to a postfix increment proxy. That is, writing *iter++ = some_value; doesn't really do anything but changing a temporary value in the proxy. In addition to this, iter++ == iter would't find a suited overload, which seems to be a bug. Chancing the traversal tag to forward traversal works correct, but that's not really what I want to do. I want my iterator to be single pass since I don't support the i == j => ++i == ++j requirement. Jens
Jens Theisen
I want to implement my own iterator as single pass traversal with reference type value& (a genuine reference).
My problem is, that the iterator facade concludes from the single pass traversal, that this is an input/output iterator
I'm afraid you're mistaken.
and those are generelly subject to a postfix increment proxy.
No, postfix increment proxies are used for any readable iterators that are not at least forward traversal iterators.
That is, writing
*iter++ = some_value;
doesn't really do anything but changing a temporary value in the proxy.
If that's the case, the iterator_facade is choosing postfix_increment_proxy instead of writable_postfix_increment_proxy, on the basis of the fact that you haven't given the iterator a proxy reference type. I'm not sure I understand the logic behind it, but iterator_facade assumes that if your readable iterator doesn't support forward traversal, it must have a proxy reference in order to also be writable. If you have a counterexample, it would be good to see it. [Jeremy, Thomas: Can you shed any light on this assumption? Also, it looks like we left out the requirement that a single-pass iterator is also an incrementable iterator. Am I mistaken? If not, I'd like to fix the docs: http://tinyurl.com/2dm3h]
In addition to this, iter++ == iter would't find a suited overload, which seems to be a bug.
That expression is not required to be supported by a single-pass iterator. See http://tinyurl.com/2dm3h.
Chancing the traversal tag to forward traversal works correct, but that's not really what I want to do. I want my iterator to be single pass since I don't support the i == j => ++i == ++j requirement.
Interesting. I'd like to know more. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
That is, writing
*iter++ = some_value;
doesn't really do anything but changing a temporary value in the proxy.
If that's the case, the iterator_facade is choosing postfix_increment_proxy instead of writable_postfix_increment_proxy, on the basis of the fact that you haven't given the iterator a proxy reference type. I'm not sure I understand the logic behind it, but iterator_facade assumes that if your readable iterator doesn't support forward traversal, it must have a proxy reference in order to also be writable. If you have a counterexample, it would be good to see it.
My reference type is a simple reference, I want to implement an lvalue iterator (at least in some cases). I am trying to make a proxy iterator that can be attached to different implementations of other iterators and compositions thereof. The problem with Forward traversal is that I can't really compare to iterators at the moment. My equals is defined as true iff both sides are empty (past the end of the sequence). :-) I thought changing this would require passing the comparison functionality through to the implementations, what I don't really want to do; in part because the implementations can be quite nested, so this would be a bit slow for something that I need solely as an end-of-sequence test. To be honest, I don't consider this a real problem anymore. I could simply attach a counter to the iterators to do the actual comparison. So, Forward traversal it is. Thank you for your assistance. Best regards, Jens
Jens Theisen
David Abrahams wrote:
That is, writing
*iter++ = some_value;
doesn't really do anything but changing a temporary value in the proxy. If that's the case, the iterator_facade is choosing postfix_increment_proxy instead of writable_postfix_increment_proxy, on the basis of the fact that you haven't given the iterator a proxy reference type. I'm not sure I understand the logic behind it, but iterator_facade assumes that if your readable iterator doesn't support forward traversal, it must have a proxy reference in order to also be writable. If you have a counterexample, it would be good to see it.
My reference type is a simple reference, I want to implement an lvalue iterator (at least in some cases).
And why is it only single-pass?
I am trying to make a proxy iterator ^^^^^^^^^^^^^^ What do you mean by that?
that can be attached to different implementations of other iterators and compositions thereof.
The problem with Forward traversal is that I can't really compare to iterators at the moment. My equals is defined as true iff both sides are empty (past the end of the sequence). :-)
I don't see why that would be incompatible with forward traversal. We don't even seem to have a requirement that a copy of an iterator compares equal with it. Perhaps we should; then you might be in trouble [Jeremy, Thomas, your thoughts?]
I thought changing this would require passing the comparison functionality through to the implementations, what I don't really want to do; in part because the implementations can be quite nested, so this would be a bit slow for something that I need solely as an end-of-sequence test.
That shouldn't be slow if there's plenty of inlining.
To be honest, I don't consider this a real problem anymore. I could simply attach a counter to the iterators to do the actual comparison. So, Forward traversal it is.
Well, I think we must have some logic errors in iterator_facade, though. This case confuses even me. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Jens Theisen
writes: My reference type is a simple reference, I want to implement an lvalue iterator (at least in some cases).
And why is it only single-pass?
I am trying to make a proxy iterator
^^^^^^^^^^^^^^ What do you mean by that?
It is a class templated on a value_type to with implementations can be attached (at run time). For example: List< char > l = makeList(some_std_string) + makeList(some_char_array); l.begin(), l.end() give you an iterator which type depends solely on the value_type (char in this case), rather than the iterator types used as backends (std::string::iterator and pointers). These iterators will iterate over the std::string first and after this over the char array.
I don't see why that would be incompatible with forward traversal. We don't even seem to have a requirement that a copy of an iterator compares equal with it. Perhaps we should; then you might be in trouble [Jeremy, Thomas, your thoughts?]
Oh, you're right. I somehow assumed that would be the case. However, this is a requirement for Forward iterators, and iterator_faced gives the forward_traversal_tag to Forward traversal iterators with reference reference type. So it maybe a good idea to add this requirement.
That shouldn't be slow if there's plenty of inlining.
The indirections are runtime indirections. Best regards, Jens
Jens Theisen
David Abrahams wrote:
Jens Theisen
writes: My reference type is a simple reference, I want to implement an lvalue iterator (at least in some cases). And why is it only single-pass?
I am trying to make a proxy iterator ^^^^^^^^^^^^^^ What do you mean by that?
It is a class templated on a value_type to with implementations can be attached (at run time). For example:
List< char > l = makeList(some_std_string) + makeList(some_char_array);
l.begin(), l.end() give you an iterator which type depends solely on the value_type (char in this case), rather than the iterator types used as backends (std::string::iterator and pointers). These iterators will iterate over the std::string first and after this over the char array.
We call that "any_iterator" (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?LibrariesUnde...)
I don't see why that would be incompatible with forward traversal. We don't even seem to have a requirement that a copy of an iterator compares equal with it. Perhaps we should; then you might be in trouble [Jeremy, Thomas, your thoughts?]
Oh, you're right. I somehow assumed that would be the case. However, this is a requirement for Forward iterators, and iterator_faced gives the forward_traversal_tag to Forward traversal iterators with reference reference type. So it maybe a good idea to add this requirement.
Yeah, I agree.
That shouldn't be slow if there's plenty of inlining.
The indirections are runtime indirections.
I see. Well, a generalized single-pass iterator can't be writable unless it has a proxy reference, IIRC. Otherwise, how does *x = a; work? -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
List< char > l = makeList(some_std_string) + makeList(some_char_array);
We call that "any_iterator" (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?LibrariesUnde...)
I think I focusing more on compounds like the above concatenation, but also filters and maps. I want to have the list expressiveness of Lisp, Haskell or Python to define what collections I want to have rather than using the stl algorithms to tell how collections are being contructed.
Well, a generalized single-pass iterator can't be writable unless it has a proxy reference, IIRC. Otherwise, how does *x = a; work?
According to the new iterator concepts it should be perfectly fine to have an lvalue access single-pass iterator. It is always up to the iterator's implementor what requirements he implements. Although I admit that this will be a rare combination and if my own iterators fall under these conditions, it's just because I'm lazy. Best regards, Jens
Jens Theisen
David Abrahams wrote:
List< char > l = makeList(some_std_string) + makeList(some_char_array); We call that "any_iterator" (see http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?LibrariesUnde...)
I think I focusing more on compounds like the above concatenation, but also filters and maps. I want to have the list expressiveness of Lisp, Haskell or Python to define what collections I want to have rather than using the stl algorithms to tell how collections are being contructed.
Well, a generalized single-pass iterator can't be writable unless it has a proxy reference, IIRC. Otherwise, how does *x = a; work?
According to the new iterator concepts it should be perfectly fine to have an lvalue access single-pass iterator.
Yes. My point is that the iterator_facade framework is making some deductions about your iterator's capabilities based on the reference type you supplied. The logic is that if *x returns a real reference, then either the iterator must not be writable, or the referenced object must persist past the iterator's lifetime and therefore the iterator could be multipass. I suppose it's possible to build a writable single-pass iterator that just throws out the data you write into it... -- Dave Abrahams Boost Consulting www.boost-consulting.com
Jens Theisen wrote:
David Abrahams wrote:
It is a class templated on a value_type to with implementations can be attached (at run time). For example:
List< char > l = makeList(some_std_string) + makeList(some_char_array);
l.begin(), l.end() give you an iterator which type depends solely on the value_type (char in this case), rather than the iterator types used as backends (std::string::iterator and pointers). These iterators will iterate over the std::string first and after this over the char array.
AFAICS it is always possible to implement a resonable operator== as long as you apply the same restriction as for std::container iterators. I.e. comparing iterators from different sequences yields undefined behaviour.
I don't see why that would be incompatible with forward traversal. We don't even seem to have a requirement that a copy of an iterator compares equal with it. Perhaps we should; then you might be in trouble [Jeremy, Thomas, your thoughts?]
Oh, you're right. I somehow assumed that would be the case. However, this is a requirement for Forward iterators, and iterator_faced gives the forward_traversal_tag to Forward traversal iterators with reference reference type. So it maybe a good idea to add this requirement.
That shouldn't be slow if there's plenty of inlining.
The indirections are runtime indirections.
You can always have a fast path for comparison to the end iterator. Regards Thomas -- Thomas Witt witt@acm.org
David Abrahams wrote:
If that's the case, the iterator_facade is choosing postfix_increment_proxy instead of writable_postfix_increment_proxy, on the basis of the fact that you haven't given the iterator a proxy reference type. I'm not sure I understand the logic behind it, but iterator_facade assumes that if your readable iterator doesn't support forward traversal, it must have a proxy reference in order to also be writable. If you have a counterexample, it would be good to see it.
[Jeremy, Thomas: Can you shed any light on this assumption?
Sorry, but no.
Also, it looks like we left out the requirement that a single-pass iterator is also an incrementable iterator. Am I mistaken? If not, I'd like to fix the docs: http://tinyurl.com/2dm3h]
Hmm, the requirements table header says: 'Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality Comparable)' Isn't that sufficient? Thomas -- Thomas Witt witt@acm.org
Thomas Witt
David Abrahams wrote:
If that's the case, the iterator_facade is choosing postfix_increment_proxy instead of writable_postfix_increment_proxy, on the basis of the fact that you haven't given the iterator a proxy reference type. I'm not sure I understand the logic behind it, but iterator_facade assumes that if your readable iterator doesn't support forward traversal, it must have a proxy reference in order to also be writable. If you have a counterexample, it would be good to see it. [Jeremy, Thomas: Can you shed any light on this assumption?
Sorry, but no.
Also, it looks like we left out the requirement that a single-pass iterator is also an incrementable iterator. Am I mistaken? If not, I'd like to fix the docs: http://tinyurl.com/2dm3h]
Hmm, the requirements table header says:
'Single Pass Iterator Requirements (in addition to Incrementable Iterator and Equality Comparable)'
Isn't that sufficient?
Yup, I'm blind. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (3)
-
David Abrahams
-
Jens Theisen
-
Thomas Witt