
On Mon, Jun 7, 2010 at 12:52 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
On 6/7/10 3:42 PM, Alfredo Correa wrote:
On Sun, Jun 6, 2010 at 4:41 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Is there a reason why you are not using plain phoenix::function(s) for this?
good point, I am still phoenix-challenged I guess. I got driven by the "Composite" example in the manual. This is the alternative implementation using phoenix::function:
namespace boost{namespace phoenix{ struct real_impl{ template<typename Arg> struct result{ typedef double type; //can be generalized }; template<typename Arg> typename result<Arg>::type operator()(Arg z) const{ return real(z); } }; function<real_impl> real_; // "real" as name doesn't work }} int main(){ std::complex<double> z(1.,2.); cout<< real_(arg1)(z)<<endl; return 0; }
which works. ...But there is a problem it seem that I can not call "real_" as "real", so the resulting syntax is degraded. (Either I have to call the phoenix::function real_ or put std::real in the operator()) It seems that the overload get confused. Is there a way to go around this? (my poorly written first version --with no phoenix::function-- at least didn't have this limitation)
Good point. Well, you can make real_ and friends use the extension mechanism as before, then use functions for all else.
I understand the underscore is necessary for reserved keywords, but using it for everything is a pity. So I stick with the solution that allows the same phoenix and (rest of) C++ the same name. In fact I realized that if I need any function (from example in std cmath) it is good to define the following macro to "register" existing functions, to be used in phoenix expressions. #include<boost/spirit/home/phoenix.hpp> #include <boost/utility/enable_if.hpp> /// Extends any endomorphic function as a phoenix function, endomorphic in the sense that the input and output are of the same type #define BOOST_PHOENIX_REGISTER_ENDOMORPHISM(FN) \ namespace boost{ \ namespace phoenix{ \ struct FN##_eval{ \ template <typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type type;}; \ template <typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FN(arg_.eval(env)); \ } \ }; \ template <typename Arg_> \ typename boost::enable_if_c<is_actor<Arg_>::value, \ actor<typename as_composite<FN##_eval, Arg_>::type> \ >::type \ FN(Arg_ const& arg_){ \ return compose<FN##_eval>(arg_); \ } \ }} and then register any arbitrary function (this solution work if the input/output type are the same. maybe with upcoming decltype we can do better). BOOST_PHOENIX_REGISTER_ENDOMORPHISM(cos); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(cosh); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(exp); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(log); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(log10); ... This could be useful to make phoenix support a large portion of STL (in this case cmath), I don't know if it is planned. Also there is no necessity of the underscore. Note two things: 1) I had to put an "enable_if_c" in order to avoid huge error messages when the function is not really defined outside Phoenix. When the function is not defined then the 'return FN(...)' line get confused with the phoenix function with the same name. 2) I have a confusion with the namespaces, the phoenix function (e.g. "cos") is in the namespace boost::phoenix which is good because the function is resolved correctly most of the time. but the real function (e.g. "std::cos") has no information about the namespace, which is good but I guess sometimes we need need to be specific of the namespace of the function we are trying to register. But adding the namespace will break the macro. One alternative is to add a second parameter to the macro so BOOST_PHOENIX_REGISTER_ENDOMORPHISM(std::cos, cos); //first the fully qualified name, second the boost::phoenix the other possibility is to try to define the phoenix function in the same namespace as the original function. The fact that a function with the same name can appear in different namespaces and the fact that there no concept of namespace in phoenix then it seems the last possibility is the only general one. Thanks, Alfredo