Boost logo

Boost :

Subject: Re: [boost] [fusion] Trouble using BOOST_FUSION_ADAPT_ADT with boost::fusion::operator<
From: Joel de Guzman (joel_at_[hidden])
Date: 2012-05-16 21:03:51


On 5/16/2012 10:44 AM, Nathan Ridge wrote:
>
>>>>>>> I'm attempting to adapt a third-party struct into a fusion sequence
>>>>>>> using BOOST_FUSION_ADAPT_ADT to get access to a nice operator<.
>>>>>>> Unfortunately compilation fails and I'm not sure if it's a bug or me
>>>>>>> using the library incorrectly. As best I can read the error message, it
>>>>>>> looks like the code is attempting to compare adt_attribute_proxy structs
>>>>>>> instead of the values represented by these. Below is some code that
>>>>>>> demonstrates the problem. Can anybody help me out?
>>>>>>>
>>>>>>
>>>>>> You've bumped into a limitation of proxies. Fusion adapted ADTs do
>>>>>> not have access to the actual L-values of the class members, but only
>>>>>> through get and set. As such, it actually exposes proxy elements
>>>>>> (adt_attribute_proxy) instead of the actual elements. The only thing
>>>>>> you can do with these proxies is either to get the values or set the
>>>>>> values:
>>>>>
>>>>> Can't Fusion provide overloads for relational operators that compare
>>>>> adt_attribute_proxy objects by comparing their values?
>>>>
>>>> Yes, that is a reasonable solution. I'd welcome a patch if anyone
>>>> wants to add such operators. I'm a bit worried about the behavior
>>>> of such operators, however. It needs to deduce the return types of
>>>> the actual (non-proxy) overloads. It can be done, but is rather
>>>> tricky without C++11.
>>>
>>> A slightly different idea: rather than provide relational operators
>>> for adt_attribute_proxy itself, add support for it to the relational
>>> opperators of Fusion sequences.
>>>
>> [...]
>>>
>>> Now the relational operators will work for ADT sequences themselves.
>>> The user will still have to call get() explicitly when comparing
>>> individual elements of the ADT sequences, but that should be rare.
>>>
>>> What do you think of this approach? It does not seem to require
>>> deducing the type of anything.
>>>
>>> If you're interested I can try this out and submit a patch.
>>
>> Clever! I like it. We can probably put the customization points
>> (e.g. call_on_values <but better names please>) in the lower level
>> "support" module in "extension" namespace. Then the "adapted"
>> module can simply specialize the CPs for adt_attribute_proxy.
>>
>> Yeah, nice idea!
>
> I implemented a slight variation of this that's a bit more general.
>
> I added a new function extension::as_readonly() in the support module,
> which unwraps wrappers like adt_attribute_proxy to get at the underlying
> value. The main template is just the identity function, but the
> adapted/adt module overloads it for adt_attribute_proxy to return
> proxy.get().
>
> I then changed the implementations of the relational operators to wrap
> accesses to the sequence elements in as_readonly() before comparing.
>
> There may be other parts of the library where it's useful to wrap
> readonly accesses of sequence elements in as_readonly() - this
> mechanism can be re-used in those parts.
>
> Users can also overload/specialize as_readonly() for their own wrapper
> classes if they find it convenient.
>
> Patch attached. Tests pass with patch.
>
> (If you have a better idea for the name of this function that
> 'as_readonly', I am happy to change it.)

The idea looks sound. I am applying the patch now. I took the liberty
to rename as_readonly to as_const.

What's lacking are tests. Could you please also provide some?

Thanks a lot!

Regards,

-- 
Joel de Guzman
http://www.boostpro.com
http://boost-spirit.com

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