Boost logo

Boost :

From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2008-05-16 13:02:17


On Fri, May 16, 2008 at 1:36 AM, Marco Costalba <mcostalba_at_[hidden]> wrote:
> On Thu, May 15, 2008 at 11:37 PM, Daniel Walker
> <daniel.j.walker_at_[hidden]> 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.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk