// Daniel Walker // May 14, 2008 #include #include #include #include #include #include #include #include #include #include #include using namespace boost; // 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 // callable object. For example, boost::function takes plain old call // signatures like int(int) - the actual signature of a resolved // function at the call site - but boost:result_of takes "polymorphic" // signatures of the form functor(int). template struct signature : mpl::identity { }; // A metafunction to generate an actual builtin, monomorphic call // signature. By default, assume Signature is in fact already a call // signature, then specialize for the wrapper above. template struct call_signature : mpl::identity { }; template struct call_signature > : function_types::function_type< mpl::push_front< mpl::pop_front< function_types::components > , typename result_of::type > > { }; // A metafunction to extract the callable object from a polymorphic // signature. By default, assume Signature is a result_of-style // signature, then specialize for the wrapper above. template struct callable_object : function_types::result_type { }; template struct callable_object > : function_types::result_type { }; // Cast between two boost::functions with different call signatures // wrapping the same polymorphic function object. template function >::type> functional_cast(function f) { typedef typename callable_object::type functor_type; functor_type const* p = f.template target(); if(!p) throw std::bad_cast(); return function >::type>(*p); } // A polymorphic call-wrapper. template struct polymorphic_function; // When given a call signature polymorphic_function acts like // boost::function and can promote second-class functions. template struct polymorphic_function { typedef function function_type; public: // Constructors for both first and second class functions polymorphic_function() {} template polymorphic_function(G g) : f(g) {} polymorphic_function(T0 (*g)(T1)) : f(g) {} typedef T0 result_type; T0 operator()(T1 t) { return f(t); } private: function_type f; }; // When given a result_of-style signature where the callable object is // polymorphic, polymorphic_function is also polymorphic but can no // longer promote builtins. Use MPL placeholders in the signature to // specify which function arguments correspond to template parameters. template struct polymorphic_function { typedef F function_type; public: // Constructor for only first-class functions, since polymorphic // second-class functions can not be promoted. polymorphic_function() {} template polymorphic_function(G g) : f(g) {} template struct result; template struct result : result_of { }; template typename result_of::type operator()(T t) { return f(t); } private: function_type f; }; // A function. int f(int i) { return i; } // A polymorphic functor. struct g { template struct result; template struct result { typedef T type; }; template T operator()(T t) { return t; } }; int main() { // Cast between functions with different call signatures. { function f0 = g(); function f1 = functional_cast(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. { using mpl::placeholders::_1; polymorphic_function f0 = f; polymorphic_function f1 = g(); polymorphic_function f2 = g(); assert(f0(1)/2 == 0); assert(f1(1)/2 == 0); assert(f1(1.0)/2 == 0); assert(f2(1)/2 == 0); assert(f2(1.0)/2 == .5); } }