From efad48c831e3ca17bf53d73a3c27875c07ee7081 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 19 Mar 2017 02:07:18 +0100 Subject: [PATCH] Function-Tools: new improved function signature trait including lambda support (#994) move the reworked solution in place, replacing the existing workarounds, partial solutions and variations --- research/try.cpp | 85 ++------ .../diff/tree-mutator-attribute-binding.hpp | 2 +- src/lib/diff/tree-mutator.hpp | 34 +--- src/lib/meta/function.hpp | 186 +++++------------- 4 files changed, 63 insertions(+), 244 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 5cfddcddc..559800e4f 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -51,6 +51,7 @@ typedef unsigned int uint; #include #include +using lib::meta::_Fun; using std::function; using std::placeholders::_1; @@ -59,60 +60,6 @@ using std::string; using std::tuple; using std::move; -////////////////############# Investigation of implementation variants -namespace lib { -namespace meta { - - template - struct _FuZ - : _FuZ - { }; - - /** Specialisation for a bare function signature */ - template - struct _FuZ - { - using Ret = RET; - using Args = Types; - using Sig = RET(ARGS...); - }; - /** Specialisation for using a function pointer */ - template - struct _FuZ - : _FuZ - { }; - - /** Specialisation when using a function reference */ - template - struct _FuZ - : _FuZ - { }; - - /** Specialisation for passing a rvalue reference */ - template - struct _FuZ - : _FuZ - { }; - - /** Specialisation to deal with member pointer to function */ - template - struct _FuZ - : _FuZ - { }; - - /** Specialisation to handle member pointer to const function; - * indirectly this specialisation also handles lambdas, - * as redirected by the main template (via `decltype`) */ - template - struct _FuZ - : _FuZ - { }; - -}}//namespace lib::meta - -using lib::meta::_FuZ; - -////////////////############# Investigation of implementation variants @@ -158,7 +105,7 @@ template void showType (F) { - using Sig = typename _FuZ::Sig; + using Sig = typename _Fun::Sig; SHOW_TYPE (F); SHOW_TYPE (Sig); @@ -168,7 +115,7 @@ template void showRef (F&) { - using Sig = typename _FuZ::Sig; + using Sig = typename _Fun::Sig; SHOW_TYPE (F); SHOW_TYPE (Sig); @@ -178,7 +125,7 @@ template void showCRef (F&) { - using Sig = typename _FuZ::Sig; + using Sig = typename _Fun::Sig; SHOW_TYPE (F); SHOW_TYPE (Sig); @@ -188,7 +135,7 @@ template void showRRef (F&&) { - using Sig = typename _FuZ::Sig; + using Sig = typename _Fun::Sig; SHOW_TYPE (F); SHOW_TYPE (Sig); @@ -258,18 +205,18 @@ main (int, char**) SHOW_TYPE (decltype(&Funky::operator())); SHOW_TYPE (decltype(lambda)); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); - using Siggy = _FuZ::Sig; - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); - SHOW_TYPE (_FuZ::Sig); + using Siggy = _Fun::Sig; + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); cout << "\n.gulp.\n"; diff --git a/src/lib/diff/tree-mutator-attribute-binding.hpp b/src/lib/diff/tree-mutator-attribute-binding.hpp index 4185bb6ea..a0e74b126 100644 --- a/src/lib/diff/tree-mutator-attribute-binding.hpp +++ b/src/lib/diff/tree-mutator-attribute-binding.hpp @@ -236,7 +236,7 @@ namespace diff{ class ChangeOperation : public AttributeBindingBase { - using CloArgs = typename _ClosureType::Args; + using CloArgs = typename lib::meta::_Fun::Args; using ValueType = typename lib::meta::Pick::Type; using ID = idi::EntryID; diff --git a/src/lib/diff/tree-mutator.hpp b/src/lib/diff/tree-mutator.hpp index a63b3bd1f..5969919e3 100644 --- a/src/lib/diff/tree-mutator.hpp +++ b/src/lib/diff/tree-mutator.hpp @@ -284,44 +284,14 @@ namespace diff{ namespace { // Mutator-Builder decorator components... - using lib::meta::Strip; - using lib::meta::Types; + using lib::meta::_Fun; using std::forward; using std::move; - /** - * Type rebinding helper to pick up the actual argument type. - * Works both for functors and for lambda expressions - * @remarks Solution proposed 10/2011 by \link http://stackoverflow.com/users/224671/kennytm user "kennytm" \endlink - * in this \link http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda/7943765#7943765 - * answer on stackoverflow \endlink - * @todo this should be integrated into (\ref _Fun) //////////////////////////////////////TICKET #994 - */ - template - struct _ClosureType - : _ClosureType - { }; - - template - struct _ClosureType - { - using Args = typename Types::Seq; - using Ret = RET; - using Sig = RET(ARGS...); - }; - - template - struct _ClosureType - { - using Args = typename Types::Seq; - using Ret = RET; - using Sig = RET(ARGS...); - }; - template struct has_Sig - : std::is_same::Sig> + : std::is_same::Sig> { }; /** verify the installed functors or lambdas expose the expected signature */ diff --git a/src/lib/meta/function.hpp b/src/lib/meta/function.hpp index 34d831dfd..b81b19050 100644 --- a/src/lib/meta/function.hpp +++ b/src/lib/meta/function.hpp @@ -26,7 +26,7 @@ ** Sometimes it is necessary to build and remould a function signature, e.g. for ** creating a functor or a closure based on an existing function of function pointer. ** This is a core task of functional programming, but sadly C++ in its current shape - ** is still lacking in this area. (C++0X will significantly improve this situation). + ** is still lacking in this area. (C++11 significantly improved this situation). ** As an \em pragmatic fix, we define here a collection of templates, specialising ** them in a very repetitive way for up to 9 function arguments. Doing so enables ** us to capture a function, access the return type and argument types as a typelist, @@ -36,7 +36,8 @@ ** If the following code makes you feel like vomiting, please look away, ** and rest assured: you aren't alone. ** - ** @todo rework to use variadic templates and integrage support for lambdas //////////////////////////////////////TICKET #994 + ** @todo get rid of the repetitive specialisations + ** and use variadic templates to represent the arguments /////////////////////////////////TICKET #994 ** ** ** @see control::CommandDef usage example @@ -215,13 +216,23 @@ namespace meta{ /** - * 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. - * @todo the base case should be a _generic functor_ where we - * pick up the signature through `decltype`, which also - * works with lambdas. See (\ref _ClosureType) //////////////////////////////////////TICKET #994 + * Helper for uniform access to function signature types. + * Extract the type information contained in a function or functor type, + * so it can be manipulated by metaprogramming. The embedded typedefs + * allow to pick up the return type, the sequence of argument types + * and the bare function signature type. This template works on + * anything _function like_, irrespective if the parameter is given + * as function reference, function pointer, member function pointer, + * functor object, `std::function` or lambda. + * + * The base case assumes a functor object, i.e. anything with an `operator()`. + * The following explicit specialisations handle the other cases, which are + * not objects, but primitive types (function (member) pointers and references). + * @remarks The key trick of this solution is to rely on `decltype` of `operator()` + * and was proposed 10/2011 by user "[kennytm]" in this [stackoverflow]. + * + * [kennytm]: http://stackoverflow.com/users/224671/kennytm + * [stackoverflow] : http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda/7943765#7943765 "answer on stackoverflow" */ template struct _Fun @@ -232,151 +243,42 @@ namespace meta{ template struct _Fun { - using Ret = typename FunctionSignature>::Ret ; - using Args = typename FunctionSignature>::Args; + using Ret = RET; + using Args = Types; using Sig = RET(ARGS...); }; /** Specialisation for using a function pointer */ template struct _Fun - { - typedef typename FunctionSignature>::Ret Ret; - typedef typename FunctionSignature>::Args Args; - typedef SIG Sig; - }; + : _Fun + { }; + /** Specialisation when using a function reference */ template struct _Fun - { - typedef typename FunctionSignature>::Ret Ret; - typedef typename FunctionSignature>::Args Args; - typedef SIG Sig; - }; - /** Specialisation for passing a functor */ + : _Fun + { }; + + /** Specialisation for passing a rvalue reference */ template - struct _Fun> - { - typedef typename FunctionSignature>::Ret Ret; - typedef typename FunctionSignature>::Args Args; - typedef SIG Sig; - }; + struct _Fun + : _Fun + { }; - /** Specialisations for member function pointers */ -/* template - struct _Fun - { - typedef RET Ret; - typedef Types Args; - typedef RET Sig(CLASS* const); - }; + /** Specialisation to deal with member pointer to function */ + template + struct _Fun + : _Fun + { }; - template< typename RET, class CLASS - , typename A1 - > - struct _Fun - { - typedef RET Ret; - typedef Types Args; - }; + /** Specialisation to handle member pointer to const function; + * indirectly this specialisation also handles lambdas, + * as redirected by the main template (via `decltype`) */ + template + struct _Fun + : _Fun + { }; - template< typename RET, class CLASS - , typename A1 - , typename A2 - > - struct _Fun - { - typedef RET Ret; - typedef Types Args; - typedef RET Sig(CLASS* const, A1,A2); - }; - - template< typename RET, class CLASS - , typename A1 - , typename A2 - , typename A3 - > - struct _Fun - { - typedef RET Ret; - typedef Types Args; - typedef RET Sig(CLASS* const, A1,A2,A3); - }; - - template< typename RET, class CLASS - , typename A1 - , typename A2 - , typename A3 - , typename A4 - > - struct _Fun - { - typedef RET Ret; - typedef Types Args; - typedef RET Sig(CLASS* const, A1,A2,A3,A4); - }; - - template< typename RET, class CLASS - , typename A1 - , typename A2 - , typename A3 - , typename A4 - , typename A5 - > - struct _Fun - { - typedef RET Ret; - typedef Types Args; - typedef RET Sig(CLASS* const, A1,A2,A3,A4,A5); - }; - - 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; - typedef RET Sig(CLASS* const, A1,A2,A3,A4,A5,A6); - }; - - 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; - typedef RET Sig(CLASS* const, A1,A2,A3,A4,A5,A6,A7); - }; - - 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; - typedef RET Sig(CLASS* const, A1,A2,A3,A4,A5,A6,A7,A8); - }; -*/ template