[Units+Lambda+Math] Functor wrappers for overloaded cmath functions to avoid static_cast in boost::lambda::bind calls

Hello, nearly three months ago, I started a thread <http://thread.gmane.org/gmane.comp.lib.boost.devel/175774> on Boost-devel to propose a header, which interfaces Boost.Units with Boost.Lambda. An improved version <boost/units/lambda.hpp> became official part of Boost.Units. However, this header only addresses the mathematical operators (+, -, *, /, ...) and not the common mathematical functions defined cmath (overloaded for boost::units::quantity<Unit, Y> in <boost/units/cmath.hpp>). In an lambda expression, their invocation needs to be postponed till the execution of the whole lambda expression, using boost::lambda::bind to bind the function arguments to the function pointer. The problem is that for overloaded functions, a lengthy static_cast is required to avoid an "unresolved overloaded function type" error as for example in the following code fragment taken from <libs/units/example/lambda.cpp>: using namespace boost::units; using namespace boost::units::si; using boost::function; using boost::lambda::bind; using boost::lambda::_1; function<quantity<current> (quantity<time>) > i = iamp * bind(static_cast<quantity<dimensionless, double> (*)( const quantity<plane_angle>&)>(sin), 2.0 * M_PI * radian * f * _1) + i0; Steven Watanabe proposed in <http://thread.gmane.org/gmane.comp.lib.boost.devel/175774> to create functor wrappers for each cmath function to allow Boost.Lambda to automatically determine the return type of the overloaded functions. As this solution is not Boost.Units specific, he proposed to put the functor wrappers under a more general place like boost::math::functional. I implemented his proposal in the attached header "boost/units/math_functional.hpp" for all the functions overloaded in <boost/units/cmath.hpp>. There is also a unit test "libs/units/test/test_math_functional.cpp" and example "libs/units/examples/math_functional_lambda.cpp". In the latter, the above code snippet simplifies down to: using namespace boost::units; using namespace boost::units::si; using boost::function; using boost::lambda::bind; using boost::lambda::_1; using boost::math::functional; using boost::units::functional; function<quantity<current> (quantity<time>) > i = iamp * bind(sin_t(), 2.0 * M_PI * radian * f * _1) + i0; The functor wrappers include either a sig template or a result_type typedef, which allows Boost::Lambda's bind to choose the correct overloaded function depending on the types passed through the lambda placeholders. The cmath function calls are not prefixed by a namespace qualifier thus allowing argument dependent lookup (ADL, a.k.a. Koenig lookup). All functor wrappers have a '_t' prefix to avoid interference with the ADL. The functor wrappers for functions from <cmath> are defined in namespace boost::math::functional (to anticipate a generalization of this header). Functor wrappers for Boost.Units specific functions are defined in boost::units::functional (for boost::units::pow<long>, boost::units::pow<Rat>, boost::units::root<long>, boost::units::root<Rat>). The implementation has still some issues: * TODO: Functor wrappers for fma, nearbyint, rint (the boost::units implementations are unfinished in trunk). * TODO: Remove limitation of functor wrapper nexttoward to only boost::units::nexttoward, which is currently implemented in terms of boost::math::nextafter because boost::math::nexttoward is not yet available. * Is there a way to organize the code to allow dropping the _t prefix of the functor wrappers so that it would not interfere with the ADL to find the correct overloaded function in the namespaces of the function arguments? The only solution I came up with was by putting using declarations for each function defined in <cmath> and <boost/units/cmath.hpp> in a cmath_ namespace and prefix the function call inside functor wrapper with this namespace, e.g.: namespace cmath_ { using std::sin; using boost::units::sin; } struct sin { template<typename Args> class sig { private: typedef typename boost::tuples::element<1, Args>::type arg1_type; BOOST_TYPEOF_NESTED_TYPEDEF(nested, \ cmath_::sin(typeof_::make<arg1_type>()))) public: typedef typename nested::type type; }; template<typename T> typename sig<typename boost::tuples::tuple<sin, T> >::type operator()(const T& arg) const { return cmath_::sin(arg); } }; However, this has the drawback, that ADL is bypassed and only functions imported into cmath_ are found. * Is there a way to merge the functors for pow<long>, pow<Rat> and root<long>, root<Rat>? Currently, they have rather long names to disambiguate between the template arguments: static_rational_pow_t<Rat>, static_integer_pow_t<long>, static_rational_root_t<Rat>, and static_integer_root_t<long>. I'm looking for comments on this solution, especially, how it can be improved and how it should be restructured to maybe become part of Boost itself. Best regards, Torsten Maehne
participants (1)
-
Torsten Maehne