From 9a0b72e8caae939b0454630e9fdc65fcb7b58a70 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 19 Mar 2017 02:29:39 +0100 Subject: [PATCH] Function-Tools: include the investigation code as unit test ...since there is not any test coverage for this trait, which turned out to be quite deeply rooted in the system by now and handles several rather subtle special cases --- research/try.cpp | 2 + src/lib/meta/function.hpp | 5 + tests/12metaprogramming.tests | 5 + .../library/meta/function-signature-test.cpp | 236 ++++++++++++++++++ 4 files changed, 248 insertions(+) create mode 100644 tests/library/meta/function-signature-test.cpp 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