Boost logo

Boost :

Subject: Re: [boost] [fusion] Trouble using BOOST_FUSION_ADAPT_ADT with boost::fusion::operator<
From: Nathan Ridge (zeratul976_at_[hidden])
Date: 2012-01-17 23:33:33


> >>> 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.

For example, for 'less than', where you have the following in
<boost/fusion/sequence/comparison/detail/less.hpp>:

template <typename I1, typename I2>
static bool
call(I1 const& a, I2 const& b, mpl::false_)
{
    return *a < *b ||
        (!(*b < *a) && call(fusion::next(a), fusion::next(b)));
}

you could instead do (untested):

template <typename I1, typename I2>

static bool

call(I1 const& a, I2 const& b, mpl::false_)

{

    return call_on_values(*a, *b) ||

        (!call_on_values(*b, *a) && call(fusion::next(a), fusion::next(b)));

}

// call_on_values() for two non-proxies
template <typename E1, typename E2>

static bool

call_on_values(E1 const& a, E2 const& b)

{

    return a < b;

}

// call_on_values() for a non-proxy and a proxy
template <typename E1, typename Seq, int Index, bool Const>
static bool
call_on_values(E1 const& a, adt_attribute_proxy<Seq, Index, Const> const& b)
{
    return a < b.get();
}

// similarly, versions for a proxy and a non-proxy, and two proxies

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.

Regards,
Nate
                                               


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