diff --git a/research/try.cpp b/research/try.cpp index 559800e4f..5be3b928d 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -36,6 +36,8 @@ /** @file try.cpp ** Metaprogramming: unified treatment of functors, function references and lambdas. + ** Rework our existing function signature trait to also support lambdas, which forces us + ** to investigate and in the end to change the handling of function member pointers. ** ** This investigation is a partial step towards #994 and became necessary to support ** Command definition by Lambda diff --git a/src/lib/meta/function.hpp b/src/lib/meta/function.hpp index b81b19050..0ca2a6374 100644 --- a/src/lib/meta/function.hpp +++ b/src/lib/meta/function.hpp @@ -230,6 +230,11 @@ namespace meta{ * 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]. + * @note for a member pointer to function, only the actual arguments in the + * function signature are reflected. But if you bind such a member + * pointer into a `std::function`, an additional first parameter + * will show up to take the `this` pointer of the class instance. + * @see FunctionSignature_test * * [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" diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests index 3ec9cfd3c..0b5892fae 100644 --- a/tests/12metaprogramming.tests +++ b/tests/12metaprogramming.tests @@ -164,6 +164,11 @@ return: 0 END +TEST "function signature trait" FunctionSignature_test < + + 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-signature-test.cpp + ** unit test \ref FunctionSignature_test + */ + + +#include "lib/test/run.hpp" +#include "lib/format-cout.hpp" +#include "lib/format-util.hpp" +#include "lib/meta/function.hpp" + +#include +#include + +using lib::meta::_Fun; + +using std::function; +using std::placeholders::_1; +using std::bind; +using std::string; +using std::tuple; +using std::move; + + +namespace lib { +namespace meta { +namespace test { + + + namespace { // test subjects +int +funny (uint i) +{ + return -i+1; +} + +struct Funky + { + int ii = 2; + + int + fun (uint i2) + { + return ii + funny(i2); + } + + int + operator() (uint i2) + { + return 2*ii - fun(i2); + } + + static int + notfunny (uint i) + { + return 2*funny (i); + } + }; + + + +#define SHOW_TYPE(_TY_) \ + cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() < +void +showType (F) + { + using Sig = typename _Fun::Sig; + + SHOW_TYPE (F); + SHOW_TYPE (Sig); + } + +template +void +showRef (F&) + { + using Sig = typename _Fun::Sig; + + SHOW_TYPE (F); + SHOW_TYPE (Sig); + } + +template +void +showCRef (F&) + { + using Sig = typename _Fun::Sig; + + SHOW_TYPE (F); + SHOW_TYPE (Sig); + } + +template +void +showRRef (F&&) + { + using Sig = typename _Fun::Sig; + + SHOW_TYPE (F); + SHOW_TYPE (Sig); + } + } // (End) test subjects + + +using Fun = function; +using Fuk = function; + + + + + + + /*********************************************************************//** + * @test verify metaprogramming trait to pick up function signature types. + * - ability to handle _function like_ entities uniformly + * - can handle function references, function pointers, + * member pointer to function, functor objects, + * `std::function` and lambdas + * - supports arbitrary number of arguments + * @see lib::meta::_Fun + * @see typelist.hpp + * @see FunctionClosure_test + */ + class FunctionSignature_test : public Test + { + virtual void + run (Arg) + { + Fun f1{funny}; + Fun f2{&funny}; + + Fun f3{Funky::notfunny}; + Fun f4{&Funky::notfunny}; + + auto memfunP = &Funky::fun; + + Fuk f5{memfunP}; + + Funky funk; + + Fun f6{bind (f5, funk, _1)}; + + auto lambda = [&](uint ii) { return funk.fun(ii); }; + + Fun f7{lambda}; + + showType (funny); + showType (&funny); + showType (Funky::notfunny); + + showType (memfunP); + showType (lambda); + showType (f7); + + cout << "\n\n-------\n"; + + showRef (funny); + showRef (lambda); + showRef (f7); + + showCRef (funny); + showCRef (lambda); + showCRef (f7); + + showRRef (move(lambda)); + showRRef (move(f7)); + + showType (move(&funny)); + showType (move(lambda)); + showType (move(f7)); + + Fun& funRef = f1; + Funky& funkyRef = funk; + Fun const& funCRef = f1; + Funky const& funkyCRef = funk; + showType (funRef); + showType (funkyRef); + showType (funCRef); + showType (funkyCRef); + + cout << "\n\n-------\n"; + + SHOW_TYPE (decltype(&Funky::operator())); + SHOW_TYPE (decltype(lambda)); + + 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 = _Fun::Sig; + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + SHOW_TYPE (_Fun::Sig); + + cout << "\n.gulp.\n"; + } + }; + + + /** Register this test class... */ + LAUNCHER (FunctionSignature_test, "unit common"); + + + +}}} // namespace lib::meta::test