/* FUNCTION-CLOSURE.hpp - metaprogramming tools for closing a function over given arguments Copyright (C) Lumiera.org 2009, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file function-closure.hpp ** Partial function application and building a complete function closure. ** This is a small addendum to (and thin wrapper for) tr1/functional, supporting ** the case when a function should be closed over (all) arguments, where especially ** the parameter values to close on are provided as a tuple. ** ** @see control::CommandDef usage example ** @see function.hpp ** @see tuple.hpp ** */ #ifndef LUMIERA_META_FUNCTION_CLOSURE_H #define LUMIERA_META_FUNCTION_CLOSURE_H #include "lib/meta/function.hpp" #include "lib/meta/tuple.hpp" #include namespace lumiera { namespace typelist{ using std::tr1::function; using std::tr1::bind; namespace func { ///< helpers for binding and applying a function to an argument tuple using tuple::element; template struct _Fun { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; template struct _Fun > { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; template struct is_Functor { static const bool value = false; }; template struct is_Functor > { static const bool value = true; }; /** * this Helper with repetitive specialisations for up to nine arguments * is used either to apply a function to arguments given as a tuple, or * to create the actual closure (functor) over all function arguments. */ template struct Apply; template<> //__________________________________ struct Apply<0> ///< Apply function without Arguments { template static RET invoke (FUN& f, TUP&) { return f (); } template static RET bind (FUN& f, TUP&) { return std::tr1::bind (f); } }; template<> //_________________________________ struct Apply<1> ///< Apply function with 1 Argument { template static RET invoke (FUN& f, TUP & arg) { return f (element<0>(arg)); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg)); } }; template<> //_________________________________ struct Apply<2> ///< Apply function with 2 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) ); } }; template<> //_________________________________ struct Apply<3> ///< Apply function with 3 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) ); } }; template<> //_________________________________ struct Apply<4> ///< Apply function with 4 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) ); } }; template<> //_________________________________ struct Apply<5> ///< Apply function with 5 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) ); } }; template<> //_________________________________ struct Apply<6> ///< Apply function with 6 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) ); } }; template<> //_________________________________ struct Apply<7> ///< Apply function with 7 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) ); } }; template<> //_________________________________ struct Apply<8> ///< Apply function with 8 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) ); } }; template<> //_________________________________ struct Apply<9> ///< Apply function with 9 Arguments { template static RET invoke (FUN& f, TUP & arg) { return f ( element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) , element<8>(arg) ); } template static RET bind (FUN& f, TUP & arg) { return std::tr1::bind (f, element<0>(arg) , element<1>(arg) , element<2>(arg) , element<3>(arg) , element<4>(arg) , element<5>(arg) , element<6>(arg) , element<7>(arg) , element<8>(arg) ); } }; } // (END) impl-namespace (func) /** * Closure-creating template. * @note taking functor objects \em and parameters per reference */ template class TupleApplicator { typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; typedef function BoundFunc; enum { ARG_CNT = count::value }; /** storing a ref to the parameter tuple */ Tuple& params_; public: TupleApplicator (Tuple& args) : params_(args) { } BoundFunc bind (SIG& f) { return func::Apply::template bind (f, params_); } BoundFunc bind (function const& f) { return func::Apply::template bind (f, params_); } Ret operator() (SIG& f) { return func::Apply::template invoke (f, params_); } Ret operator() (function& f) { return func::Apply::template invoke (f, params_); } }; /** * Closing a function over its arguments. * This is a small usage example or spin-off, * having almost the same effect than invoking tr1::bind. * The notable difference is that the function arguments for * creating the closure are passed in as one compound tuple. */ template class FunctionClosure { typedef typename func::_Fun::Args Args; typedef typename func::_Fun::Ret Ret; function closure_; public: FunctionClosure (SIG& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } FunctionClosure (function const& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } Ret operator() () { return closure_(); } typedef Ret result_type; ///< for STL use typedef void argument_type; }; namespace func { // ...some convenience shortcuts template struct _Sig { typedef typename FunctionTypedef::Sig Type; typedef TupleApplicator Applicator; }; template struct _Clo { typedef typename _Fun::Ret Ret; typedef typename _Sig::Type Signature; typedef FunctionClosure Type; }; /** build a TupleApplicator, which embodies the given * argument tuple and can be used to apply various * functions to them. */ template typename _Sig::Applicator tupleApplicator (Tuple& args) { typedef typename _Sig::Type Signature; return TupleApplicator (args); } /** apply the given function to the argument tuple */ template typename _Fun::Ret apply (SIG& f, Tuple& args) { typedef typename _Fun::Ret Ret; // typedef typename _Sig::Type Signature; // Note: deliberately re-building the Signature Type return TupleApplicator (args) (f); // in order to get better error messages here } /** close the given function over all arguments, * using the values from the argument tuple. * @return a closure object, which can be * invoked later to yield the * function result. */ template typename _Clo::Type closure (SIG& f, Tuple& args) { typedef typename _Fun::Ret Ret; typedef typename _Sig::Type Signature; typedef typename _Clo::Type Closure; return Closure (f,args); } } }} // namespace lumiera::typelist #endif