From 9bba3667633b10a349792b12568b47ac1f8e0578 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 7 Jan 2012 03:28:12 +0100 Subject: [PATCH] investigate partial application of member functions --- research/try.cpp | 178 ++++++++++++++++++------------ src/lib/meta/function-closure.hpp | 117 ++++++++++++++++++++ 2 files changed, 227 insertions(+), 68 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 763f90caa..d03b9d2da 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -22,100 +22,142 @@ // 10/11 - simple demo using a pointer and a struct // 11/11 - using the boost random number generator(s) // 12/11 - how to detect if string conversion is possible? +// 1/12 - is partial application of member functions possible? -#include "lib/util.hpp" +/** @file try.cpp + ** Research: perform a partial application of a member function. + ** The result of this partial application should be a functor expecting the remaining arguments. + ** The idea was to use this at various library functions expecting a functor or callback, so to + ** improve readability of the client code: clients could then just pass a member pointer, without + ** the need to use any tr1::bind expression. + ** + ** \par Costs in code size + ** While this turned out to be possible, even without much work, just based on the existing + ** templates for partial functor application (function-closure.hpp), the resulting code size + ** is rather sobering. Especially in debug mode, quite some overhead is created, which makes + ** usage of this convenience feature in general purpose library code rather questionable. + ** When compiling with -O3 though, most of the overhead will be removed + ** + ** The following numbers could be observed: + ** \code + ** debug / stripped // debug-O3 / stripped + ** just using a member pointer: 39013 / 7048 42061 / 7056 + ** using tr1::bind and function: 90375 / 15416 65415 / 9376 + ** partial apply, passing functor: 158727 / 23576 97479 / 11296 + ** partial apply with mem pointer: 119495 / 17816 78031 / 9440 + ** \endcode + */ + +#include "lib/meta/tuple.hpp" +#include "lib/meta/function-closure.hpp" + +//#include #include -#include + +using lib::meta::Types; +using lib::meta::Tuple; +//using std::tr1::placeholders::_1; +//using std::tr1::placeholders::_2; +using std::tr1::function; +using std::tr1::bind; using std::string; using std::cout; using std::endl; -typedef char Yes_t; -struct No_t { char more_than_one[4]; }; +namespace lib { +namespace meta{ +namespace func{ -template -struct _can_convertToString +template +struct _PupS { - static TY & probe(); + typedef typename _Fun::Ret Ret; + typedef typename _Fun::Args::List Args; + typedef typename Splice::Front ArgsFront; + typedef typename Splice::Back ArgsBack; + typedef typename Types::Seq ArgsToClose; + typedef typename Types::Seq ArgsRemaining; + typedef typename _Sig::Type ReducedSignature; - static Yes_t check(string); - static No_t check(...); + typedef function Function; + }; + +template +inline +typename _PupS::Function +papply (SIG f, A1 a1) +{ + typedef typename _PupS::ArgsToClose ArgsToClose; + typedef Tuple ArgTuple; + ArgTuple val(a1); + return PApply::bindFront (f, val); +} + +template +inline +typename _PupS::Function +papply (SIG f, A1 a1, A2 a2) +{ + typedef typename _PupS::ArgPrefix ArgsToClose; + typedef Tuple ArgTuple; + ArgTuple val(a1,a2); + return PApply::bindFront (f, val); +} + + +}}} // namespace lib::meta::func + +class Something + { + int i_; + + void + privateFun(char a) + { + char aa(a + i_); + cout << "Char-->" << aa < FunP; + + FunP + getBinding() + { +// function memf = bind (&Something::privateFun, _1, _2); +// return lib::meta::func::papply (memf, this); + return lib::meta::func::papply (&Something::privateFun, this); + } + +// typedef void (Something::*FunP) (char); +// +// FunP +// getBinding() +// { +// return &Something::privateFun; +// } }; -template -bool -investigate (TY const&) - { - return _can_convertToString::value; - } - -#define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (investigate(_EXPR_)? "Yes":"No") << endl; int main (int, char**) { + Something some(23); + Something::FunP fup = some.getBinding(); - SHOW_CHECK (string("nebbich")); - SHOW_CHECK ("gurks"); - SHOW_CHECK (23.34); - SHOW_CHECK (23); - - string urgs("urgs"); - string & urgs_ref (urgs); - string const& urgs_const_ref (urgs); - string * urgs_ptr = &urgs; - - SHOW_CHECK (urgs_ref); - SHOW_CHECK (urgs_const_ref); - SHOW_CHECK (*urgs_ptr); - - SubString sub; - Something thing; - const SomehowStringy stringy = SomehowStringy(); - SomehowSubSub subsub; - SubString const& subRef(subsub); - - SHOW_CHECK (sub); - SHOW_CHECK (thing); - SHOW_CHECK (stringy); - SHOW_CHECK (subsub); - SHOW_CHECK (subRef); + fup ('a'); cout << "\n.gulp.\n"; diff --git a/src/lib/meta/function-closure.hpp b/src/lib/meta/function-closure.hpp index 572eb32fa..4b75a2f54 100644 --- a/src/lib/meta/function-closure.hpp +++ b/src/lib/meta/function-closure.hpp @@ -67,18 +67,26 @@ namespace func{ using tuple::element; + /** + * Helper to dissect an arbitrary function signature, + * irrespective if the parameter is given as function reference, + * function pointer, member function pointer or functor object. + * The base case assumes a (language) function reference. + */ template struct _Fun { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; + /** Specialisation for using a function pointer */ template struct _Fun { typedef typename FunctionSignature >::Ret Ret; typedef typename FunctionSignature >::Args Args; }; + /** Specialisation for passing a functor */ template struct _Fun > { @@ -86,6 +94,115 @@ namespace func{ typedef typename FunctionSignature >::Args Args; }; + /** Specialisations for member function pointers */ + template + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + , typename A4 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + , typename A6 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + , typename A6 + , typename A7 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET, class CLASS + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + , typename A6 + , typename A7 + , typename A8 + > + struct _Fun + { + typedef RET Ret; + typedef Types Args; + }; + + template struct is_Functor { static const bool value = false; }; template