Boost logo

Boost :

Subject: Re: [boost] [iterator] iterator_facade reference type problem
From: Phil Endecott (spam_from_boost_dev_at_[hidden])
Date: 2010-01-15 06:37:52


Jeffrey Hellrung wrote:
> Phil Endecott wrote:
>> I've done some more experiments, and it seems to work with
>> std::pair<const KEY, value&> if i write (*iter).second rather than
>> iter->second.
>>
>> Looking at the iterator_facade source, operator-> calls operator* and
>> passes the result to operator_arrow_result::make(). This takes its
>> address and, because std::pair<const KEY,VALUE&> is not a reference, it
>> tries to convert it to operator_arrow_proxy<...>. This fails because
>> std::pair<const KEY,VALUE&> is not convertible to std::pair<KEY,VALUE>.
>>
>> I think I just want operator-> to return a pointer to my reference type,
>> but the operator_arrow_result stuff is trying to do something more
>> complicated. In what case is the operator_arrow_proxy useful? Is there
>> some way to get what I want using iterator_facade?
> <snip>
>> BTW I have been testing with an oldish version of Boost, but I've looked
>> at the source in svn and it doesn't seem to have changed much.
>>
>>
>> Cheers, Phil.
>>
>
> (Also looking at the code) operator_array_proxy should be probably be
> instantiated with the Reference, not ValueType...??? Would that be
> correct? I.e., operator_array_proxy should wrap a reference (which is
> not a real C++ reference), not a value...
>
> You *could* just overload operator-> in the derived class to do
> something else (in this case, I would say try using a proxy that wraps a
> reference).
>
> Also, just to be clear, the operator_array_proxy stuff in
> iterator_facade fails not because std::pair< const KEY, VALUE& > isn't
> convertible to std::pair< KEY, VALUE >, but because their pointers
> aren't convertible. At least that's what I'm seeing...
>
> Seems like I stumbled on this in the past and rather than figure out
> what was wrong, I just redefined operator-> in the derived class to work...

Hi Jeff,

s/operator_array_proxy/operator_arrow_proxy/g

There seem to be a couple of issues here. Firstly, as you say
operator_arrow_proxy is being instantiated with the ValueType but there
would be more chance of it working if it were instantiated with the Reference.

Secondly, std::pair containing a non-const reference for the value
causes a "forming reference to reference" error in
is_convertible<pair<KEY,VALUE&>,pair<KEY,VALUE>>
(is_convertible_basic_impl gcc version; is_convertible.hpp line 137).
Is this a SFINAE issue? This is being called from
iterator_facade_default_category "check for readability". I'm out of
my depth trying to track this down any further.

I have fixed it, presumably as you did, with a custom pair-like type
and a custom arrow_proxy type, something like this:

struct iter_ref_t { // replacement for std::pair
   const KEY first;
   VALUE& second;
   iter_ref_t(const KEY first_, VALUE& second_): first(first_),
second(second_) {}
};

class iterator:
   public boost::iterator_facade<iterator,
                                 std::pair<KEY,VALUE>,
                                 boost::bidirectional_traversal_tag,
                                 iter_ref_t>
{
   iter_ref_t dereference() const { return iter_ref_t(....); }

   struct arrow_proxy { // replacement for iterator_facade::operator_arrow_proxy
     mutable iter_ref_t r;
     arrow_proxy(const iter_ref_t& r_): r(r_) {}
     iter_ref_t* operator->() const { return &r; }
   };

public:
   arrow_proxy operator->() const { // override version in iterator_facade
     return arrow_proxy(dereference());
   }

};

Would any Boost.Iterator experts care to comment?

BTW it seems to me that the operator_arrow_proxy thing is really a sort
of "smart pointer" - it's an object that looks like a pointer, but it
always points to an object that it contains. Does it have more general applications?

Regards, Phil.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk