
On Fri, May 16, 2008 at 1:36 AM, Marco Costalba <mcostalba@gmail.com> wrote:
On Thu, May 15, 2008 at 11:37 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote: I would say that for it to be equivalent to
function<int(int,int)> f0 = *add_floats.target<plus>();
It may be
return function<typename call_signature<signature<Signature>
::type>(boost::ref(*p));
instead of
return function<typename call_signature<signature<Signature> >::type>(*p);
because boost::function makes a copy as default, so you have one copy of *p in the boost::function c'tor in the return type and another, outside functional_cast in the assignment
function<int(int,int)> f0 = functional_cast<...>(..);
Excellent point. Thanks! However, you don't need (and you don't necessarily want...) the reference_wrapper when returning the new function. Actually, the return statement can be reduced to return *p, since the new boost::function in the return type is constructable from *p. Doh! ;-) This still doesn't take care of boost::function's continuous copying of the wrapped function object. However, as you know, boost::function handles reference_wrapped function objects to allow users to eliminate this overhead. So, functional_cast should also handle reference_wrapped function objects. Unfortunately, result_of does not handle reference_wrapped function objects! The workaround is simple (by the way, this is largely due to Tobias Schwinger function_types library... so thanks!), though it would also be simple to add reference_wrapped function object support to result_of. If there's interests I can add a feature request to Track and submit a patch. Anyway, the modifications I made in response to your comments are below. This can still be improved upon. For instance, the constness of the original reference_wrapper is not propagated correctly, but this suffices as a proof of concept. Daniel Walker --- polymorphic_function.cpp~ 2008-05-16 12:17:13.795000000 -0400 +++ polymorphic_function.cpp 2008-05-16 12:53:10.892000000 -0400 @@ -8,6 +8,7 @@ #include <boost/function_types/components.hpp> #include <boost/function_types/function_type.hpp> #include <boost/function_types/result_type.hpp> +#include <boost/mpl/at.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/pop_front.hpp> @@ -16,6 +17,23 @@ using namespace boost; +template<class Signature> +struct workaround_result_of_reference_wrapper_issue { + typedef typename function_types::function_type< + typename mpl::push_front< + mpl::pop_front< + function_types::components<Signature> + > + , typename unwrap_reference< + typename mpl::at< + function_types::components<Signature> + , mpl::int_<0> + >::type + >::type + > + >::type type; +}; + // A wrapper for a "polymorphic" signature, which has no fixed return // type but instead uses the return type position of builtin call // signatures to specify the type of a potentially polymorphic @@ -43,7 +61,11 @@ mpl::pop_front< function_types::components<Signature> > - , typename result_of<Signature>::type + , typename result_of< + typename workaround_result_of_reference_wrapper_issue< + Signature + >::type + >::type > > { }; @@ -67,10 +89,11 @@ function<typename call_signature<signature<Signature> >::type> functional_cast(function<CallSignature> f) { - typedef typename callable_object<Signature>::type functor_type; - functor_type const* p = f.template target<functor_type>(); + typedef typename callable_object<Signature>::type callable_object_type; + typedef typename unwrap_reference<callable_object_type>::type functor_type; + functor_type * p = f.template target<functor_type>(); if(!p) throw std::bad_cast(); - return function<typename call_signature<signature<Signature> >::type>(*p); + return is_reference_wrapper<callable_object_type>::value ? ref(*p) : *p; } @@ -145,6 +168,17 @@ assert(f1(1)/2 == .5); } + // Cast while respecting reference_wrapper. + { + g f; + function<int(int)> f0 = ref(f); + function<float(float)> f1 + = functional_cast<reference_wrapper<g>(float)>(f0); + + assert(f0(1)/2 == 0); + assert(f1(1)/2 == .5); + } + // Polymorphic function behaves like boost::function when // instantiated with a call signature and is polymorphic with a // "polymorphic" signature.