[phoenix][units] make boost.phoenix play well with boost.units
I have and expression of type arg1*arg1 which is contained in a deduced type LambdaExp (more preciselly composite<multiplies_eval,vector<argument<0>, argument<0> >) when trying to see what is the phoenix-deduced return type when input is double typename LambdaExp::template result<basic_environment<double> >::type naturally, it gives 'double' (double*double) but when the input type is a boost::units::quantity typename LambdaExp::template result<basic_environment<quantity<si::length> > >::type it gives: error_cant_deduce_type (instread of the equivalent of quantity<si::area>, like in quantity<si::area> a = quantity<si::length>()*quantity<si::length>() ) this is strange since it seemed that Phoenix worked out of the box with Units. What is going on? How can we help Phoenix deduce the return type? Does Phoenix need this help, like Boost.Lambda does by means of boost/ units/lambda.hpp? Thank you, Alfredo
On 6/3/10 6:11 PM, alfC wrote:
I have and expression of type
arg1*arg1
which is contained in a deduced type LambdaExp (more preciselly composite<multiplies_eval,vector<argument<0>, argument<0> >)
when trying to see what is the phoenix-deduced return type when input is double
typename LambdaExp::template result<basic_environment<double> >::type
naturally, it gives 'double' (double*double)
but when the input type is a boost::units::quantity
typename LambdaExp::template result<basic_environment<quantity<si::length> > >::type
it gives:
error_cant_deduce_type (instread of the equivalent of quantity<si::area>, like in quantity<si::area> a = quantity<si::length>()*quantity<si::length>() )
this is strange since it seemed that Phoenix worked out of the box with Units.
What is going on? How can we help Phoenix deduce the return type? Does Phoenix need this help, like Boost.Lambda does by means of boost/ units/lambda.hpp?
Could you please post a minimal cpp file for this one too? You are right, it should work out of the box. Not sure, but it might be a bug. Phoenix2 type deduction, while better than Lambda, is still unwieldy. This will all be fixed in 3.0. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
typename LambdaExp::template result<basic_environment<quantity<si::length> > >::type
it gives:
error_cant_deduce_type (instread of the equivalent of quantity<si::area>, like in quantity<si::area> a = quantity<si::length>()*quantity<si::length>() )
Could you please post a minimal cpp file for this one too?
this is a minimal example: #include<boost/spirit/home/phoenix.hpp> #include<iostream> #include<typeinfo> #include<boost/units/systems/si.hpp> using namespace boost::phoenix; using namespace boost::phoenix::arg_names; using namespace boost::units; template<class LambdaExp> void expression_analizer(actor<LambdaExp> l){ std::clog <<"type of argument expression: " <<typeid(LambdaExp).name()<<std::endl; std::clog<<"type of return on double: " <<typeid( typename LambdaExp::template result<basic_environment<double>
::type ).name()<<std::endl; std::clog<<"type of return on quantity<length>: " <<typeid( typename LambdaExp::template result<basic_environment<quantity<si::length> > >::type ).name()<<std::endl; std::clog<<"... should be "<< typeid( quantity<si::length>()*quantity<si::length>() ).name() <<std::endl }
int main(){ expression_analizer(arg1*arg1); return 0; } /*************end of example**************************/
On 6/4/10 9:02 AM, alfC wrote:
typename LambdaExp::template result<basic_environment<quantity<si::length> > >::type
it gives:
error_cant_deduce_type (instread of the equivalent of quantity<si::area>, like in quantity<si::area> a = quantity<si::length>()*quantity<si::length>() )
Could you please post a minimal cpp file for this one too?
this is a minimal example:
[snip] When you do a*a with quantity<si::length>, what is the expected return type? (looks like a phoenix-2 limitation. hopefully, this will all get sorted out with phoenix-3). Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
AMDG Joel de Guzman wrote:
When you do a*a with quantity<si::length>, what is the expected return type?
quantity<si::area>
(looks like a phoenix-2 limitation. hopefully, this will all get sorted out with phoenix-3).
In Christ, Steven Watanabe
On Jun 3, 7:16 pm, Steven Watanabe <watanab...@gmail.com> wrote:
Joel de Guzman wrote:
When you do a*a with quantity<si::length>, what is the expected return type?
quantity<si::area> rigth.
and in case you wonder, Boost.Units has a bunch of template functions to obtain the result type of arithmetic operations. For example boost::units::multiply_typeof_helper<X,Y>::type, these are heavily used in boost/units/lambda.hpp, which makes lambda play well with units.
(looks like a phoenix-2 limitation. hopefully, this will all get sorted out with phoenix-3).
so, there is no hope with phoenix-2? can't we do something temporary like boost/units/lambda.hpp to help phoenix-2 to deduce the type? is it possible? Thank you, Alfredo
On 6/4/10 10:31 AM, alfC wrote:
On Jun 3, 7:16 pm, Steven Watanabe<watanab...@gmail.com> wrote:
Joel de Guzman wrote:
When you do a*a with quantity<si::length>, what is the expected return type?
quantity<si::area> rigth.
and in case you wonder, Boost.Units has a bunch of template functions to obtain the result type of arithmetic operations. For example boost::units::multiply_typeof_helper<X,Y>::type, these are heavily used in boost/units/lambda.hpp, which makes lambda play well with units.
(looks like a phoenix-2 limitation. hopefully, this will all get sorted out with phoenix-3).
so, there is no hope with phoenix-2? can't we do something temporary like boost/units/lambda.hpp to help phoenix-2 to deduce the type? is it possible?
There is hope. Just specialize boost::phoenix::result_of_xxx (e.g. boost::phoenix::result_of_plus<X, Y>). See phoenix/operator/arithmetic.hpp for example. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
On Jun 3, 7:52 pm, Joel de Guzman <j...@boost-consulting.com> wrote:
On 6/4/10 10:31 AM, alfC wrote: There is hope. Just specialize boost::phoenix::result_of_xxx (e.g. boost::phoenix::result_of_plus<X, Y>).
I specilized result_of_multiplies and still no luck: #include<boost/spirit/home/phoenix.hpp> #include<iostream> #include<typeinfo> #include<boost/units/systems/si.hpp> namespace boost{ namespace phoenix{ using namespace boost::units; template<> //in general template<class XUnit, class YUnit> struct result_of_multiplies<quantity<si::length>, quantity<si::length>
{ typedef quantity<si::area> type; }; }}
using namespace boost::phoenix; using namespace boost::phoenix::arg_names; using namespace boost::units; template<class LambdaExp> void expression_analizer(actor<LambdaExp> l){ std::clog <<"type of argument expression: " <<typeid(LambdaExp).name()<<std::endl; std::clog<<"type of return on double: " <<typeid( typename LambdaExp::template result< basic_environment<double> >::type ).name()<<std::endl; std::clog <<"type of return on quantity<length>: " <<typeid( typename LambdaExp::template result< basic_environment< quantity<si::length> > >::type ).name()<<std::endl; std::clog<<"... should be "<< typeid( quantity<si::length>()*quantity<si::length>() ).name() <<std::endl; } int main(){ expression_analizer(arg1*arg1); return 0; }
On 6/5/10 6:01 AM, alfC wrote:
On Jun 3, 7:52 pm, Joel de Guzman<j...@boost-consulting.com> wrote:
On 6/4/10 10:31 AM, alfC wrote: There is hope. Just specialize boost::phoenix::result_of_xxx (e.g. boost::phoenix::result_of_plus<X, Y>). I specilized result_of_multiplies and still no luck:
#include<boost/spirit/home/phoenix.hpp> #include<iostream> #include<typeinfo> #include<boost/units/systems/si.hpp>
namespace boost{ namespace phoenix{ using namespace boost::units; template<> //in general template<class XUnit, class YUnit> struct result_of_multiplies<quantity<si::length>, quantity<si::length>
{ typedef quantity<si::area> type; }; }}
The type-deduction respects references. Phoenix2 passes in references. The code should be: template<> //in general template<class XUnit, class YUnit> struct result_of_multiplies<quantity<si::length>&, quantity<si::length>&> { typedef quantity<si::area> type; }; Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
The type-deduction respects references. Phoenix2 passes in references. The code should be:
template<> //in general template<class XUnit, class YUnit> struct result_of_multiplies<quantity<si::length>&, quantity<si::length>&> { typedef quantity<si::area> type; };
::type type; }; template<class XUnit, class Y, class TX> struct result_of_multiplies<quantity<XUnit,TX>&, Y&>{ typedef typename multiply_typeof_helper<quantity<XUnit,TX>&,Y& ::type type; }; template<class XUnit, class YUnit , class TX, class TY> struct result_of_divides<quantity<XUnit>&, quantity<YUnit>&>{ typedef typename
can you believe it?, I tried with 'const &' but not '&'!!! Thank you so much for your help. Boost.Units and Boost.Interval will be good benchmark test for the type deduction of Phoenix3 (what will be the magic of P3? use of typeof?) Below it is a bridge code between phoenix2 and units. Notes: 1) Not sure about the reference '&' in the typedefs, put them there for symmetry. 2) result_of_plus/minus don't seem to be necessary 3) todo: overload operator*(actor<T>, quantity<...>) and operator*(actor<T>, unit<...>) and reversed to overcome ambiguity on operator*. 4) todo: specialize *=, /= 5) I wish this be in boost/units/phoenix2.hpp. // phoenix2 units bridge, result_of_plus/minus don't seem to be necesary, todo: *=, /= namespace boost{ namespace phoenix{ using namespace boost::units; template<class XUnit, class YUnit, class TX, class TY> struct result_of_multiplies<quantity<XUnit,TX>&, quantity<YUnit,TY>&>{ typedef typename multiply_typeof_helper<quantity<XUnit,TX>&,quantity<YUnit,TY>& >::type type; }; template<class X, class YUnit,class TY> struct result_of_multiplies<X&, quantity<YUnit,TY>&>{ typedef typename multiply_typeof_helper<X&,quantity<YUnit,TY>& divide_typeof_helper<quantity<XUnit,TX>&,quantity<YUnit,TY>& >::type type; }; template<class X, class YUnit> struct result_of_divides<X&, quantity<YUnit,TY>&>{ typedef typename divide_typeof_helper<X&,quantity<YUnit,TY>&
::type type; }; template<class XUnit, class Y> struct result_of_divides<quantity<XUnit,TX>&, Y&>{ typedef typename divide_typeof_helper<quantity<XUnit,TX>&, Y&>::type type; }; }}
On 6/4/2010 8:55 PM, alfC wrote:
Thank you so much for your help. Boost.Units and Boost.Interval will be good benchmark test for the type deduction of Phoenix3 (what will be the magic of P3? use of typeof?)
Yes. Phoenix 3 will be forward-looking in this regard. Most compilers at least support Boost.Typeof, and many now have decltype. Type deduction will be automatic in most cases; at worst, you may need to register your user-defined types with Boost.Typeof. -- Eric Niebler BoostPro Computing http://www.boostpro.com
On Jun 4, 5:55 pm, alfC <alfredo.cor...@gmail.com> wrote:
The type-deduction respects references. Phoenix2 passes in references. The code should be:
template<> //in general template<class XUnit, class YUnit> struct result_of_multiplies<quantity<si::length>&, quantity<si::length>&> { typedef quantity<si::area> type; };
Actually (unfortunately) it seems that all 4 combinations of reference/ no reference are needed. This is the only way I managed to make these expression work with type deduction: arg1*arg1 (arg1*arg1)*arg1 arg1*(arg1*arg1) (arg1*arg1)*(arg1*arg1) 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 Jun 4, 5:55 pm, alfC <alfredo.cor...@gmail.com> 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 }}
On Jul 16, 3:09 am, Alfredo Correa <alfredo.cor...@gmail.com> wrote:
namespace boost{ namespacephoenix{ #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 is a bit more generic: #define RESULT_OF_QUANTITY_UNITS_GEN( PhoenixopnamE, UnitsopnamE ) \ template< \ typename X, \ class Dim, class System> \ struct result_of_##PhoenixopnamE < \ X&, \ boost::units::unit<Dim, System> \
{ \ typedef \ typename boost::units::UnitsopnamE##_typeof_helper< \ X, \ 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
On 6/4/10 10:16 AM, Steven Watanabe wrote:
AMDG
Joel de Guzman wrote:
When you do a*a with quantity<si::length>, what is the expected return type?
quantity<si::area>
(looks like a phoenix-2 limitation. hopefully, this will all get sorted out with phoenix-3).
Ok, phoenix-2's type deduction can't deduce that alright. Sorry. Best you can do is specialize boost::phoenix::result_of_xxx for your types. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
participants (5)
-
alfC
-
Alfredo Correa
-
Eric Niebler
-
Joel de Guzman
-
Steven Watanabe