[iterator] indirect_iterator->

I have a question on the indirect_iterator, and what related standards say. I assume this class is primarily aimed for use in algorithms, which is fine. An algorithm typically dereference an iterator to do its thing, be it comparing or passing the dereferenced iterator on to a function or functor. This is great. But it doesn't handle direct usage well. If I have an indirect_iterator i for, say, a pointer to std::string, I cannot treat it as any other iterator to string and empty the string with this call: i->clear(); because the pointer operator is not changed. Instead you have to dereference it and use it as a reference: (*i).clear(); It seems strange to me that one way of getting hold of the iterated object is provided, but not the other. I couldn't find anything about this in a brief look through the standard, but I would expect it to want iterators yield the same results for both formats. Does anybody know if it does say anything on this subject, and why operator->() wasn't included in indirect_iterator? Cheers, Orjan

Orjan Westin wrote:
I have a question on the indirect_iterator, and what related standards say.
There is no standard that covers indirect_iterator as such.
I assume this class is primarily aimed for use in algorithms, which is fine. An algorithm typically dereference an iterator to do its thing, be it comparing or passing the dereferenced iterator on to a function or functor. This is great.
But it doesn't handle direct usage well.
??
If I have an indirect_iterator i for, say, a pointer to std::string, I cannot treat it as any other iterator to string and empty the string with this call: i->clear(); because the pointer operator is not changed. Instead you have to dereference it and use it as a reference: (*i).clear();
int main() { std::string s("Foo"); std::vector<std::string*> rgP; rgP.push_back(&s); boost::make_indirect_iterator(rgP.begin())->clear(); std::cerr << s << '\n'; } Works for me what did I miss?
Does anybody know if it does say anything on this subject, and why operator->() wasn't included in indirect_iterator?
It would be helpful if you would include compiler/platform boost version in your report. Regards Thomas -- Thomas Witt witt@acm.org

"Orjan Westin" <orjan.westin@gmx.net> writes:
I have a question on the indirect_iterator, and what related standards say.
I assume this class is primarily aimed for use in algorithms, which is fine. An algorithm typically dereference an iterator to do its thing, be it comparing or passing the dereferenced iterator on to a function or functor. This is great.
But it doesn't handle direct usage well.
If I have an indirect_iterator i for, say, a pointer to std::string, I cannot treat it as any other iterator to string and empty the string with this call: i->clear(); because the pointer operator is not changed.
It certainly is changed appropriately.
Instead you have to dereference it and use it as a reference: (*i).clear();
Can you post a minimal reproducible example that shows the problem you're describing? Your description is not consistent with the way indirect_iterator was designed, so either something is wrong with your example or you have found a bug in the library. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Orjan Westin" <orjan.westin@gmx.net> writes:
I have a question on the indirect_iterator, and what related standards say.
I assume this class is primarily aimed for use in algorithms, which is fine. An algorithm typically dereference an iterator to do its thing, be it comparing or passing the dereferenced iterator on to a function or functor. This is great.
But it doesn't handle direct usage well.
If I have an indirect_iterator i for, say, a pointer to std::string, I cannot treat it as any other iterator to string and empty the string with this call: i->clear(); because the pointer operator is not changed.
It certainly is changed appropriately.
My apologies, I should have said I have only read the documentation - this question was intended for the boost user list, not the developer one. The documentation only shows the dereferencing and talk about dereferencing, and somehow I got the impression this was all it did. The pointer operator is not mentioned in the documentation, as far as I could see.
Instead you have to dereference it and use it as a reference: (*i).clear();
Can you post a minimal reproducible example that shows the problem you're describing? Your description is not consistent with the way indirect_iterator was designed, so either something is wrong with your example or you have found a bug in the library.
No, something was wrong with my question, and possibly the documentation. I've made a little test to confirm it, and it works as it should. Just out of curiosity, do you ever think you (and the "you" here is the boost community, not you David) fall for the temptation to do things more powerful and complex than they need be? Just looking at the <counts> 14-18 includes in indirect_header.hpp is a bit scary, really, and personally I found the code a bit hard to follow. This is not unique to the iterator library either - I often get a feeling when looking at things in boost and other publicly accessible libraries that things are somethimes done not so much because that's what needs to be done, but because they are interesting, technologically challenging or cool. I know I sometimes find myself overengineering simply because I think "wouldn't it be cool if..." I apologise for the concern I caused unecessarily, and for the rambling reply. Orjan

"Orjan Westin" <orjan.westin@gmx.net> writes:
No, something was wrong with my question, and possibly the documentation. I've made a little test to confirm it, and it works as it should.
You're right; the documentation is wrong, or at least very obtuse. In the synopsis for indirect_iterator, it only shows the parts of the interface that are added to what it inherits from iterator_adaptor, and iterator_adaptor is not shown as a base. The only hint you have is in: http://www.boost.org/libs/iterator/doc/indirect_iterator.html#indirect-itera... which, in combination with the standard iterator requirements, actually tells you that operator-> is present.
Just out of curiosity, do you ever think you (and the "you" here is the boost community, not you David) fall for the temptation to do things more powerful and complex than they need be?
Why would that be tempting?
Just looking at the <counts> 14-18 includes in indirect_header.hpp is a bit scary, really
Why? Most of those headers define a single component whose name corresponds exactly to the header name. Would you rather see #include <big_mess_o_stuff.hpp> instead?
, and personally I found the code a bit hard to follow.
The first motivation in producing the library is to make it as useful and useable as possible. Occasionally code clarity suffers. However, in this case -- aside from more comments which would be nice -- I can't see how the clarity could be improved. I certainly don't see how fewer #includes would aid clarity.
This is not unique to the iterator library either - I often get a feeling when looking at things in boost and other publicly accessible libraries that things are somethimes done not so much because that's what needs to be done, but because they are interesting, technologically challenging or cool. I know I sometimes find myself overengineering simply because I think "wouldn't it be cool if..."
Feel free to design something simpler that works just as well, if you think it can be done. Often, to provide easy-to-use interfaces, libraries need to do complicated things in their implementations. The fact that the docs were not quite adequate in this case aside, users are expected to understand the libraries from their documentation. Libraries are not written primarily so that users will be able to understand their implementations, but so that they will provide users with the best service. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
"Orjan Westin" <orjan.westin@gmx.net> writes:
You're right; the documentation is wrong, or at least very obtuse. In the synopsis for indirect_iterator, it only shows the parts of the interface that are added to what it inherits from iterator_adaptor, and iterator_adaptor is not shown as a base. The only hint you have is in:
http://www.boost.org/libs/iterator/doc/indirect_iterator.html#indirect-itera...
which, in combination with the standard iterator requirements, actually tells you that operator-> is present.
Yes, but for those of us who do not have a copy of the standard, it could do with making it a tad more explicit, if I may say so.
Just out of curiosity, do you ever think you (and the "you" here is the boost community, not you David) fall for the temptation to do things more powerful and complex than they need be?
Why would that be tempting?
The messages I've seen about adding hex dump to the logging library lately illustrate what I mean, I think.
Just looking at the <counts> 14-18 includes in indirect_header.hpp is a bit scary, really
Why? Most of those headers define a single component whose name corresponds exactly to the header name. Would you rather see
#include <big_mess_o_stuff.hpp>
instead?
No, of course not. But since I found the documentation unclear, I thought I have a look at the code, and seeing this many dependencies for what I at first thought ought to be a relatively straightforward couple of classes was intimidating, since I would have to follow a fair few of those includes to be able to understand the code.
, and personally I found the code a bit hard to follow.
The first motivation in producing the library is to make it as useful and useable as possible.
Granted. A library user should never have reason to look at the code. This puts a lot of demands on the documentation, though.
Occasionally code clarity suffers. However, in this case -- aside from more comments which would be nice -- I can't see how the clarity could be improved. I certainly don't see how fewer #includes would aid clarity.
By itself, reducing the number of #includes wouldn't do anything. The code would still be quite complex, and require an understanding of pointee, mpl, ia_dflt_help in order to be understood.
This is not unique to the iterator library either - I often get a feeling when looking at things in boost and other publicly accessible libraries that things are somethimes done not so much because that's what needs to be done, but because they are interesting, technologically challenging or cool. I know I sometimes find myself overengineering simply because I think "wouldn't it be cool if..."
Feel free to design something simpler that works just as well, if you think it can be done.
I don't think it can be done. I've been using something I wrote some years ago, and it has served me well enough, but it's far from as powerful. It's quite small and simple to understand, though. The reason I had a look at the boost::indirect_iterator was that I've been preparing something I thought I'd release in the wild, and so it might be a good idea to use the standard one instead of mine.
Often, to provide easy-to-use interfaces, libraries need to do complicated things in their implementations. The fact that the docs were not quite adequate in this case aside, users are expected to understand the libraries from their documentation.
Agreed.
Libraries are not written primarily so that users will be able to understand their implementations, but so that they will provide users with the best service.
And again, I agree. I did not mean to critisise - as I said, it was just idle curiosity. Cheers, Orjan
participants (3)
-
David Abrahams
-
Orjan Westin
-
Thomas Witt