Howdy,
Dave sent me a forward to this conversation some time ago and I have
finally made the time to catch up on the conversation and contribute my
two cents. The issues that Tobias describes regarding operator-> are,
I believe, exactly the same issues I encountered while implementing
Boost.MultiArray.
To use an earlier version of iterator adaptors, I had to supply a
modified copy of the library as part of MultiArray's implementation.
Using the more recent version of iterator adaptors, I simply had to
implement my own operator->() member function and operator_arrow_proxy
object. Clearly I can implement the behavior I want using the library
as-is.
The question of interest then seems to be the following: Should
iterator adaptors somehow more explicitly take my and Tobias'
implementation needs into consideration? Perhaps the library's default
behavior when Reference is not a true reference type should be changed;
Perhaps a FAQ entry in the documentation would suffice. Since I can
make my library work correctly today with little pain or code
duplication, I'm not particularly passionate about this case.
With respect to the greater language issue, let me respond to an
earlier statement by Dave:
"If iterator_facade handed you a pointer to non-const value_type, it
would allow you to modify this temporary, which would then disappear.
We don't do that for the same reasons the language won't bind a
non-const reference to a temporary."
Around here (the Open Systems Lab at Indiana University), I've been
arguing against this property of C++ for a long time, specifically that
the language does not allow you to bind temporary to a non-const
reference. I am under the impression that this behavior is meant to
"protect" the programmer from making certain mistakes, but the grave
downside to this is that it also prevents a library writer from using
proxy objects to mimic reference semantics.
Taking an example from MultiArray, if I have an 2x2 multidimensional
array:
boost::multi_array
Tobias Schwinger wrote:
David Abrahams wrote:
But why not just change the interface in your dereference function and hand back a real reference at that point? If you are not storing a copy of the value_type within the proxy, I don't see what the proxy can be buying you.
I'll put a short problem-domain-specific excursion at the end of this post which explains what exactly the proxy is buying me.
Thanks.
So now we come to this one. This one is entirely in the hands of the library to prevent, since the user doesn't usually determine the return type of operator->. It seems like a bad idea to allow it silently. The library is supplying an operator-> that stores an object of the value_type. There are very few situations where modifications to that object can go anywhere useful, so it makes sense to prevent them.
Doesn't the fact that reference and value_type are the same and both are mutable class types indicate that this should work as well ?
Ah. Well now, that is a special case. Maybe we should allow it whenever reference is the same as or derived from value_type. Incidentally, I don't call that case a proxy -- as far as I'm concerned that's just an ordinary non-lvalue iterator. I suppose if your value_type is really a refcounted pimpl it is somewhat proxy-like, though. Incidentally #2, the library is focused mainly on building generic iterators so we usually didn't consider the fact that class value_type objects returned by value from an iterator's operator* might be assigned into.
After all, it should be just another notation for
(*i).mutator(value)
from a user's perspective.
The library is able to make sensible default choices without fear because the user can always reimplement any operator within his derived iterator.
My workaround to allow it feels somewhat ugly, because I have to redundantly do the same thing iterator_facade does already (use yet another proxy to aggregate my temporary reference object and make its operator-> return a pointer to it - just like operator_arrow_proxy (given that reference and value_type are the same), except that there is a non-const operator->, too).
Understandable.
!!! However, it works for me. I don't want to try to make you change things for what could be a special case !!!
I'm not too sure calling mutators on a proxy class really is that special, though.
It's not so special, but building a proxy reference that fully emulates the interface of the referenced value type is quite unusual. It's takes a lot of work, is very fragile and can't be done generically.
...and I can't imagine there is a user who would seriously complain that
pointer ptr ( i.operator->().operator->() );
gives an invalid pointer ;-).
Am I missing something ?
There was a guy who complained just last week on this very mailing list that putting an iterator_adaptor over a T const* suddenly produced writability in the iterator through operator-> !! http://lists.boost.org/MailArchives/boost-users/msg08656.php
Yeah, I (partially) read it to ensure I am not asking redundant questions before starting this thread. I still believe adapting pointers is a different story.
It's not such a different story. If I take a non-writable version your iterator, operating correctly, and wrap iterator_adaptor around it, it would be very strange if operator-> allowed you to mutate members.
Excursion: what's the proxy buying me ?
I use a generic, resizable container (similar to std::vector but with memory layout guarantees) to feed vector data to my graphics board through some rendering API. The proxy allows me to see a vector object instead of a reference to an array of floating type.
Operating on plain arrays in order to perform vector arithmetics is quite unhandy. Using a converting constructor from a reference to array type is a radical and error prone approach and would restrict me to use only one class for vector arithmetics (there is no way to tell if float[3] should be a homogenous 2D-vector or a non-homogenous 3D-vector, for example).
That's why I use a vector-reference proxy class that allows me to work on vectors whose data lives somewhere else.
I understand, thanks.
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users