Boost logo

Boost Users :

Subject: Re: [Boost-users] [phoenix][units] make boost.phoenix play well with boost.units
From: Alfredo Correa (alfredo.correa_at_[hidden])
Date: 2010-07-16 06:09:01


> On Jun 4, 5:55 pm, alfC <alfredo.cor..._at_[hidden]> wrote:
> So, I have to implement this kind of macro sorcery to bridge
> Boost.Units and Boost.Phoenix. Not sure if I will find another bump in
> the road:
>
> namespace boost{
> namespace phoenix{
> using namespace boost::units;
> #define RESULT_OF_GEN( PhoenixnamE, UnitsnamE, RefQ1, RefQ2 ) \
>        template<class XUnit, class YUnit, class TX, class TY> \
>        struct result_of_##PhoenixnamE <quantity<XUnit,TX> RefQ1,
> quantity<YUnit,TY> RefQ2>{ \
>                typedef typename
> UnitsnamE##_typeof_helper<quantity<XUnit,TX>&,quantity<YUnit,TY>&
>>::type type; \
>        };
>        RESULT_OF_GEN(multiplies, multiply, &,  )
>        RESULT_OF_GEN(multiplies, multiply, &, &)
>        RESULT_OF_GEN(multiplies, multiply,  ,  )
>        RESULT_OF_GEN(multiplies, multiply,  , &)
>        RESULT_OF_GEN(divides   , divide  , &,  )
>        RESULT_OF_GEN(divides   , divide  , &, &)
>        RESULT_OF_GEN(divides   , divide  ,  ,  )
>        RESULT_OF_GEN(divides   , divide  ,  , &)
> #undef RESULT_OF_GEN
> }}

On top of what is above, I had to add the code below in order to be
able to use Phoenix in this context:

 using namespace boost::units;
 using namespace boost::phoenix;
 using namespace boost::phoenix::arg_names;
 ...
 boost::function<quantity<si::area>(quantity<si::length>)> f = arg1 * si::meter;
 cout << f(4.*si::meter) <<endl;

note that the improvement is that now I can use boost units names (not
only quantities) directly in a phoenix expression,
not only that the overload operator* is deduced in favor of operator*
in the phoenix (lambda sense) instead of generating
quantity<unit, actor< > > (which may or may not make sense, seems not to).
(I used boost::function just to make the example clear).

Here is the code to make this work, i.e. use phoenix and units in a
expression, (sorry again if I am not supposed to mess with phoenix
internals in this way):
namespace boost{
namespace phoenix{
#define RESULT_OF_QUANTITY_UNITS_GEN( PhoenixopnamE, UnitsopnamE ) \
template<class XUnit, typename TX, class Dim, class System> \
struct result_of_##PhoenixopnamE < \
        boost::units::quantity<XUnit,TX> &, \
        boost::units::unit<Dim, System> \
>{ \
        typedef \
                typename boost::units::UnitsopnamE##_typeof_helper< \
                        boost::units::quantity<XUnit,TX>, boost::units::unit<Dim, System> \
>::type type; \
};
        RESULT_OF_QUANTITY_UNITS_GEN(multiplies, multiply)
        RESULT_OF_QUANTITY_UNITS_GEN(divides , divide )
#undef RESULT_OF_QUANTITY_UNITS_GEN

// this refines the operator* so the phoenix:;operator* is used
instead of units::operator*
#define REFINE_ARITHMETIC_OPERATORS(PhoenixopnamE, CsymboL) \
template< \
        class PhoenixExpr, \
        class System, \
    class Dim \
> \
actor< \
        composite< \
                PhoenixopnamE##_eval, \
                boost::fusion::vector< \
                        PhoenixExpr, \
                        value< \
                                boost::units::unit<Dim, System> \
> \
> \
> \
> \
operator CsymboL (const actor<PhoenixExpr>& lhs, const unit<Dim,System>& rhs){ \
    return compose<PhoenixopnamE##_eval>(lhs, rhs); \
}
REFINE_ARITHMETIC_OPERATORS(multiplies, *)
REFINE_ARITHMETIC_OPERATORS(divides, /)
#undef REFINE_ARITHMETIC_OPERATORS
}}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net