$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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.