|
Boost : |
From: Torsten Maehne (Torsten.Maehne_at_[hidden])
Date: 2008-08-19 13:51:03
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk