From 32b740cd400127b1d119b1e4bab490e063aa4f3e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 22 Nov 2023 22:11:59 +0100 Subject: [PATCH] Library: RandomDraw - dynamic configuration requires partial application Investigation in test setup reveals that the intended solution for dynamic configuration of the RandomDraw can not possibly work. The reason is: the processing function binds back into the object instance. This implies that RandomDraw must be *non-copyable*. So we have to go full circle. We need a way to pass the current instance to the configuration function. And the most obvious and clear way would be to pass it as function argument. Which however requires to *partially apply* this function. So -- again -- we have to resort to one of the functor utilities written several years ago; and while doing so, we must modernise these tools further, to support perfect forwarding and binding of reference arguments. --- src/lib/meta/function-closure.hpp | 172 ++++++--- src/lib/meta/function.hpp | 105 ++++-- src/lib/random-draw.hpp | 11 +- src/steam/control/argument-tuple-accept.hpp | 2 +- src/steam/control/command-signature.hpp | 20 +- src/steam/control/memento-tie.hpp | 20 +- tests/library/meta/function-closure-test.cpp | 4 +- .../meta/function-composition-test.cpp | 58 +++- tests/library/random-draw-test.cpp | 108 ++++-- wiki/thinkPad.ichthyo.mm | 327 ++++++++++++++++++ 10 files changed, 683 insertions(+), 144 deletions(-) diff --git a/src/lib/meta/function-closure.hpp b/src/lib/meta/function-closure.hpp index 74d5d18f0..1e0980b10 100644 --- a/src/lib/meta/function-closure.hpp +++ b/src/lib/meta/function-closure.hpp @@ -35,7 +35,13 @@ ** ** @todo the implementation is able to handle partial application with N arguments, ** but currently we need just one argument, thus only this case was wrapped - ** up into a convenient functions func::applyFirst and func::applyLast + ** up into a convenient functions func::applyFirst and func::applyLast + ** @todo 11/23 these functor-utils were written at a time when support for handling + ** generic functions in C++ was woefully inadequate; at that time, we neither + ** had Lambda-support in the language, nor the ability to use variadic arguments. + ** Providing a one-shot function-style interface for this kind of manipulations + ** is still considered beneficial, and thus we should gradually modernise + ** the tools we want to retain... ** ** @see control::CommandDef usage example ** @see function.hpp @@ -50,6 +56,7 @@ #include "lib/meta/tuple-helper.hpp" #include +#include #include @@ -58,8 +65,10 @@ namespace lib { namespace meta{ namespace func{ - using std::function; using std::tuple; + using std::function; + using std::forward; + using std::move; @@ -607,8 +616,8 @@ namespace func{ public: - typedef function::Sig> LeftReducedFunc; - typedef function::Sig> RightReducedFunc; + typedef function::Sig> LeftReducedFunc; + typedef function::Sig> RightReducedFunc; /** do a partial function application, closing the first arguments
@@ -670,7 +679,7 @@ namespace func{ using PreparedArgTypes = typename Types::Seq; using RemainingArgs = typename Types::Seq; - using ReducedSig = typename FunctionTypedef::Sig; + using ReducedSig = typename BuildFunType::Sig; template using IdxSelector = typename PartiallyInitTuple::template IndexMapper; @@ -694,10 +703,12 @@ namespace func{ namespace { // ...helpers for specifying types in function declarations.... + using std::get; + template struct _Sig { - typedef typename FunctionTypedef::Sig Type; + typedef typename BuildFunType::Sig Type; typedef TupleApplicator Applicator; }; @@ -712,32 +723,92 @@ namespace func{ template struct _Chain { - typedef typename _Fun::Args Args; - typedef typename _Fun::Ret Ret; - typedef typename FunctionTypedef::Sig ChainedSig; - typedef function Functor; + using Ret = typename _Fun::Ret; + using Args = typename _Fun::Args; + + using FunType = typename BuildFunType::Fun; + static auto adaptedFunType() { return FunType{}; } + + + template + static auto + composedFunctions (F1&& f1, F2&& f2, _Fun) + { + tuple binding{forward (f1) + ,forward (f2) + }; + return [binding = move(binding)] + (ARGS ...args) mutable -> RET + { + auto& functor1 = get<0>(binding); + auto& functor2 = get<1>(binding); + // + return functor2 (functor1 (forward (args)...)); + }; + } }; - template + template struct _PapS { - typedef typename _Fun::Ret Ret; - typedef typename _Fun::Args Args; - typedef typename Split::Head Arg; - typedef typename Split::Tail Rest; - typedef typename _Sig::Type Signature; - typedef function Function; + using Ret = typename _Fun::Ret; + using Args = typename _Fun::Args; + using Arg = typename Split::Head; + using Rest = typename Split::Tail; + + using FunType = typename BuildFunType::Fun; + static auto adaptedFunType() { return FunType{}; } + + + template + static auto + bindFrontArg (F&& fun, A&& arg, _Fun) + { + tuple binding{forward (fun) + ,forward (arg) + }; + return [binding = move(binding)] + (ARGS ...args) mutable -> RET + { + auto& functor = get<0>(binding); + // + return functor ( forward (get<1>(binding)) + , forward (args)...); + }; + } }; - template + template struct _PapE { - typedef typename _Fun::Ret Ret; - typedef typename _Fun::Args Args; - typedef typename Split::End Arg; - typedef typename Split::Prefix Rest; - typedef typename _Sig::Type Signature; - typedef function Function; + using Ret = typename _Fun::Ret; + using Args = typename _Fun::Args; + using Arg = typename Split::End; + using Rest = typename Split::Prefix; + + using FunType = typename BuildFunType::Fun; + static auto adaptedFunType() { return FunType{}; } + + + template + static auto + bindBackArg (F&& fun, A&& arg, _Fun) + { + tuple binding{forward (fun) + ,forward (arg) + }; + return [binding = move(binding)] + (ARGS ...args) mutable -> RET + { + auto& functor = get<0>(binding); + // + return functor ( forward (args)... + , forward (get<1>(binding))); + }; + } }; } // (End) argument type shortcuts @@ -761,7 +832,8 @@ namespace func{ } - /** apply the given function to the argument tuple */ + /** apply the given function to the argument tuple + * @deprecated 11/23 meanwhile provided by the standard lib! */ template inline typename _Fun::Ret @@ -774,7 +846,7 @@ namespace func{ /** close the given function over all arguments, * using the values from the argument tuple. - * @return a closure object, which can be + * @return a closure object, which can be * invoked later to yield the * function result. */ template @@ -788,29 +860,25 @@ namespace func{ /** close the given function over the first argument */ - template - inline - typename _PapS::Function - applyFirst (SIG& f, ARG arg) + template + inline auto + applyFirst (FUN&& fun, ARG&& arg) { - typedef typename _PapS::Arg ArgType; - typedef Types ArgTypeSeq; - typedef Tuple ArgTuple; - ArgTuple val(arg); - return PApply::bindFront (f, val); + static_assert (_Fun(), "expect something function-like"); + return _PapS::bindFrontArg (forward (fun) + ,forward (arg) + ,_PapS::adaptedFunType()); } /** close the given function over the last argument */ - template - inline - typename _PapE::Function - applyLast (SIG& f, ARG arg) + template + inline auto + applyLast (FUN&& fun, ARG&& arg) { - typedef typename _PapE::Arg ArgType; - typedef Types ArgTypeSeq; - typedef Tuple ArgTuple; - ArgTuple val(arg); - return PApply::bindBack (f, val); + static_assert (_Fun(), "expect something function-like"); + return _PapE::bindBackArg (forward (fun) + ,forward (arg) + ,_PapE::adaptedFunType()); } @@ -818,7 +886,7 @@ namespace func{ * which especially might be a (nested) binder... */ template inline - typename _PapE::Function + typename _PapE::FunType::Functor bindLast (SIG& f, TERM const& arg) { typedef Types ArgTypeSeq; @@ -836,14 +904,12 @@ namespace func{ inline auto chained (FUN1&& f1, FUN2&& f2) { - using Ret = typename _Chain::Ret; - - return [functor1 = std::forward (f1) - ,functor2 = std::forward (f2)] - (auto&& ...args) -> Ret - { - return functor2 (functor1 (std::forward (args)...)); - }; + static_assert (_Fun(), "expect something function-like for function-1"); + static_assert (_Fun(), "expect something function-like for function-2"); + using Chain = _Chain; + return Chain::composedFunctions (forward (f1) + ,forward (f2) + ,Chain::adaptedFunType()); } diff --git a/src/lib/meta/function.hpp b/src/lib/meta/function.hpp index db71df0dd..e22e1544b 100644 --- a/src/lib/meta/function.hpp +++ b/src/lib/meta/function.hpp @@ -185,6 +185,29 @@ namespace meta{ + /** abbreviation for referring to a function's return type */ + template + using _FunRet = typename _Fun::Ret; + + namespace { + template + struct _DetectSingleArgFunction + { + static_assert(_Fun() , "something funktion-like required"); + static_assert(_Fun::ARITY == 1 , "function with exactly one argument required"); + + using Sig = typename _Fun::Sig; + using Arg = typename _Fun::Args::List::Head; + }; + } + + /** abbreviation for referring to a function's single Argument type */ + template + using _FunArg = typename _DetectSingleArgFunction::Arg; + + + + /** * Meta-function to check that some _function like_ entity * offers the expected signature @@ -303,24 +326,28 @@ namespace meta{ * @param ARGS a type sequence describing the arguments */ //////////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types variadic, then replace this by a single variadic template template - struct FunctionTypedef; + struct BuildFunType; template< typename RET> - struct FunctionTypedef > + struct BuildFunType > { - typedef function Func; - typedef RET Sig(); + using Sig = RET(void); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; template< typename RET , typename A1 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1); + using Sig = RET(A1); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -328,10 +355,12 @@ namespace meta{ , typename A1 , typename A2 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2); + using Sig = RET(A1,A2); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -340,10 +369,12 @@ namespace meta{ , typename A2 , typename A3 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3); + using Sig = RET(A1,A2,A3); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -353,10 +384,12 @@ namespace meta{ , typename A3 , typename A4 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4); + using Sig = RET(A1,A2,A3,A4); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -367,10 +400,12 @@ namespace meta{ , typename A4 , typename A5 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5); + using Sig = RET(A1,A2,A3,A4,A5); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -382,10 +417,12 @@ namespace meta{ , typename A5 , typename A6 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5,A6); + using Sig = RET(A1,A2,A3,A4,A5,A6); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -398,10 +435,12 @@ namespace meta{ , typename A6 , typename A7 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5,A6,A7); + using Sig = RET(A1,A2,A3,A4,A5,A6,A7); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -415,10 +454,12 @@ namespace meta{ , typename A7 , typename A8 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5,A6,A7,A8); + using Sig = RET(A1,A2,A3,A4,A5,A6,A7,A8); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; @@ -433,10 +474,12 @@ namespace meta{ , typename A8 , typename A9 > - struct FunctionTypedef> + struct BuildFunType> { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5,A6,A7,A8,A9); + using Sig = RET(A1,A2,A3,A4,A5,A6,A7,A8,A9); + using Fun = _Fun; + using Func = function; + using Functor = Func; }; diff --git a/src/lib/random-draw.hpp b/src/lib/random-draw.hpp index 4b6a06379..464ddb7c9 100644 --- a/src/lib/random-draw.hpp +++ b/src/lib/random-draw.hpp @@ -341,6 +341,7 @@ namespace lib { using Res = typename lib::meta::_Fun::Ret; using lib::meta::func::chained; + using lib::meta::_FunRet; if constexpr (std::is_same_v)// ◁──────────────────────────┨ function produces result directly return std::forward(fun); @@ -355,13 +356,13 @@ namespace lib { ,[this](double rand){ return limited(rand); } ); else - if constexpr (std::is_same_v)// ◁─────────────┨ function yields parametrised RandomDraw to invoke + if constexpr (std::is_same_v)// ◁────────────────────┨ function yields parametrised RandomDraw to invoke return [functor=std::forward(fun), this] - (auto&& ...inArgs) - { // invoke with copy - RandomDraw const& parametricDraw = functor(inArgs...); + (auto&& ...inArgs) -> _FunRet + { // invoke with copy + RandomDraw parametricDraw = functor(inArgs...); return parametricDraw (forward (inArgs)...); - }; // forward arguments + }; // forward arguments else static_assert (not sizeof(Res), "unable to adapt / handle result type"); NOTREACHED("Handle based on return type"); diff --git a/src/steam/control/argument-tuple-accept.hpp b/src/steam/control/argument-tuple-accept.hpp index cea55056b..271437534 100644 --- a/src/steam/control/argument-tuple-accept.hpp +++ b/src/steam/control/argument-tuple-accept.hpp @@ -506,7 +506,7 @@ namespace control { { using Args = typename Types::Seq; using Ret = void; - using Sig = typename FunctionTypedef::Sig; + using Sig = typename BuildFunType::Sig; using ArgTuple = std::tuple; }; diff --git a/src/steam/control/command-signature.hpp b/src/steam/control/command-signature.hpp index ab98065a9..20f1c5401 100644 --- a/src/steam/control/command-signature.hpp +++ b/src/steam/control/command-signature.hpp @@ -61,7 +61,7 @@ namespace control { using std::function; - using lib::meta::FunctionTypedef; + using lib::meta::BuildFunType; using lib::meta::_Fun; using lib::meta::Types; using lib::meta::Append; @@ -84,9 +84,9 @@ namespace control { using ExtendedArgs = typename Types::Seq; public: - using OperateSig = typename FunctionTypedef::Sig; - using CaptureSig = typename FunctionTypedef::Sig; - using UndoOp_Sig = typename FunctionTypedef::Sig; + using OperateSig = typename BuildFunType::Sig; + using CaptureSig = typename BuildFunType::Sig; + using UndoOp_Sig = typename BuildFunType::Sig; using CmdArgs = Args; using Memento = MEM; }; @@ -124,9 +124,9 @@ namespace control { using ExtendedArglist = typename Append::List; using ExtendedArgs = typename Types::Seq; - using OperateSig = typename FunctionTypedef::Sig; - using CaptureSig = typename FunctionTypedef::Sig; - using UndoOp_Sig = typename FunctionTypedef::Sig; + using OperateSig = typename BuildFunType::Sig; + using CaptureSig = typename BuildFunType::Sig; + using UndoOp_Sig = typename BuildFunType::Sig; }; /** Case2: defining the actual Undo function */ template @@ -138,9 +138,9 @@ namespace control { using OperationArglist = typename SplitLast::List; using OperationArgs = typename Types::Seq; - using OperateSig = typename FunctionTypedef::Sig; - using CaptureSig = typename FunctionTypedef::Sig; - using UndoOp_Sig = typename FunctionTypedef::Sig; + using OperateSig = typename BuildFunType::Sig; + using CaptureSig = typename BuildFunType::Sig; + using UndoOp_Sig = typename BuildFunType::Sig; }; public: diff --git a/src/steam/control/memento-tie.hpp b/src/steam/control/memento-tie.hpp index 50f70f97a..303d0ae43 100644 --- a/src/steam/control/memento-tie.hpp +++ b/src/steam/control/memento-tie.hpp @@ -72,7 +72,7 @@ namespace control { * the undo and capture function, setting up the necessary bindings and closures for * allowing them to cooperate behind the scenes to carry out the UNDO functionality. * On construction, the UndoMutation functor retrieves the wired up functions, - * storing them into generic containers (type erasure) for later invocation. + * storing them into generic containers (type erasure) for later invocation. * * More specifically, the \c captureFunction, which is expected to run immediately prior * to the actual command operation, returns a \b memento value object (of unspecific type), @@ -143,29 +143,27 @@ namespace control { * @note similar to #getState(), the returned functor will throw * when the state capturing wasn't yet invoked */ - function + function tieUndoFunc() { using std::bind; return bindLast( undo_ // getState() bound to last argument of undo(...) , bind (&MementoTie::getState, this) - ); + ); } /** bind the capturing function to the internal memento store within this object. * @return a functor, which on invocation will automatically store the return value * of the capturing function (= the current memento value) into the field - * #memento_ within this object + * #memento_ within this object */ function tieCaptureFunc() { - using std::placeholders::_1; - - function doCaptureMemento = bind (&MementoTie::capture, this, _1 ); - - return chained(capture_, doCaptureMemento); + return chained(capture_ + ,[this](MEM const& mementoVal){ capture (mementoVal); } + ); } @@ -183,7 +181,7 @@ namespace control { /** conversion to bool() yields true - * if all functions are usable and + * if all functions are usable and * memento state has been captured */ explicit @@ -203,7 +201,7 @@ namespace control { }; - + template MementoTie::operator std::string() const { diff --git a/tests/library/meta/function-closure-test.cpp b/tests/library/meta/function-closure-test.cpp index b36e4c99d..2b4bedb32 100644 --- a/tests/library/meta/function-closure-test.cpp +++ b/tests/library/meta/function-closure-test.cpp @@ -149,7 +149,7 @@ namespace test { typedef Prepend, Args>::Seq NewArgs; // manipulate the argument type(s) DISPLAY (NewArgs); - typedef FunctionTypedef::Sig NewSig; // re-build a new function signature + typedef BuildFunType::Sig NewSig; // re-build a new function signature NewSig& fun = getNumberz<1,5,9>; //...which is compatible to an existing real function signature! @@ -337,7 +337,7 @@ namespace test { // finally combine all techniques.... using NumberzArg = Types::Seq; - using NumberzSig = FunctionTypedef::Sig; + using NumberzSig = BuildFunType::Sig; Tuple numberzTup (Num<5>(22), Num<6>(33), Num<7>(44)); diff --git a/tests/library/meta/function-composition-test.cpp b/tests/library/meta/function-composition-test.cpp index 863f7b612..e1a3ebbb2 100644 --- a/tests/library/meta/function-composition-test.cpp +++ b/tests/library/meta/function-composition-test.cpp @@ -39,6 +39,8 @@ namespace meta { namespace test { using ::test::Test; + using lib::test::showType; + using lib::meta::_Fun; using func::applyFirst; using func::applyLast; using func::bindLast; @@ -142,10 +144,12 @@ namespace test { virtual void run (Arg) { - check_diagnostics (); - check_partialApplication (); - check_functionalComposition (); - check_bindToArbitraryParameter (); + check_diagnostics(); + check_partialApplication(); + check_functionalComposition(); + check_bindToArbitraryParameter(); + + verify_referenceHandling(); } @@ -383,6 +387,52 @@ namespace test { CHECK (1+2+3+4+88 == f_bound_5 (_1_,_2_,_3_,_4_ ) ); } + + /** @internal static function to pass as reference for test */ + static long floorIt (float it) { return long(floor (it)); } + + + /** @test ensure reference types and arguments are handled properly */ + void + verify_referenceHandling() + { + int ii = 99; + float ff = 88; + auto fun = std::function{[](float& f, int& i, long l) -> double { return f + i + l; }}; + auto& f1 = fun; + + // build chained and a partially applied functors + auto chain = func::chained(f1,floorIt); + auto pappl = func::applyFirst (f1, ff); + + using Sig1 = _Fun::Sig; + using SigC = _Fun::Sig; + using SigP = _Fun::Sig; + + CHECK (showType() == "double (float&, int&, long)"_expect); + CHECK (showType() == "long (float&, int&, long)"_expect); + CHECK (showType() == "double (int&, long)"_expect); + + CHECK (220 == f1 (ff,ii,33)); + CHECK (220 == chain(ff,ii,33)); + CHECK (220 == pappl( ii,33)); + + // change original values to prove that references were + // passed and stored properly in the adapted functors + ii = 22; + ff = 42; + + CHECK ( 97 == f1 (ff,ii,33)); + CHECK ( 97 == chain(ff,ii,33)); + CHECK ( 97 == pappl( ii,33)); + + // can even exchange the actual function, since f1 was passed as reference + fun = [](float& f, int& i, size_t s) -> double { return f - i - s; }; + + CHECK (-13 == f1 (ff,ii,33)); + CHECK (-13 == chain(ff,ii,33)); + CHECK (-13 == pappl( ii,33)); + } }; diff --git a/tests/library/random-draw-test.cpp b/tests/library/random-draw-test.cpp index 47780e29a..067d73096 100644 --- a/tests/library/random-draw-test.cpp +++ b/tests/library/random-draw-test.cpp @@ -42,6 +42,7 @@ namespace test{ using util::_Fmt; using lib::time::FSecs; using lib::time::TimeVar; + using lib::meta::_FunRet; @@ -78,7 +79,7 @@ namespace test{ build (FUN&& fun) { return [functor=std::forward(fun)] - (size_t hash) + (size_t hash) -> _FunRet { return functor(uint(hash/64), uint(hash%64)); }; @@ -94,7 +95,7 @@ namespace test{ build (FUN&& fun) { return [functor=std::forward(fun)] - (size_t hash) + (size_t hash) -> _FunRet { return functor(hash, ctxParameter); }; @@ -693,37 +694,90 @@ namespace test{ + template + auto + _applyFirst (FUN&& fun, ARG&& arg, _Fun) + { + std::tuple binding{std::forward (fun) + ,std::forward(arg) + }; + return [binding = std::move(binding)] + (ARGS ...args) mutable -> RET + { + auto& functor = std::get<0> (binding); + // + return functor ( std::forward (std::get<1> (binding)) + , std::forward (args)...); + }; + } + + template + auto + applyFirst (FUN&& fun, ARG&& arg) + { + using Ret = typename lib::meta::_Fun::Ret; + using AllArgs = typename lib::meta::_Fun::Args; + using RestArgs = typename lib::meta::Split::Tail; + using AdaptedFun = typename lib::meta::BuildFunType::Fun; + + return _applyFirst( std::forward (fun) + , std::forward (arg) + , AdaptedFun{}); + } + /** @test TODO change the generation profile dynamically * @todo WIP 11/23 🔁 define ⟶ implement */ void verify_dynamicChange() { - UNIMPLEMENTED ("change the generation profile dynamically"); -SHOW_EXPR(int(d2( 0))); -SHOW_EXPR(int(d2( 1))); -SHOW_EXPR(int(d2( 2))); -SHOW_EXPR(int(d2( 3))); -SHOW_EXPR(int(d2( 4))); -SHOW_EXPR(int(d2( 5))); -SHOW_EXPR(int(d2( 6))); -SHOW_EXPR(int(d2( 7))); -SHOW_EXPR(int(d2( 8))); -SHOW_EXPR(int(d2( 9))); -SHOW_EXPR(int(d2(10))); -SHOW_EXPR(int(d2(63))); -SHOW_EXPR(int(d2(64))); -SHOW_EXPR(int(d2(65))); -SHOW_EXPR(int(d2(66))); -SHOW_EXPR(int(d2(67))); -SHOW_EXPR(int(d2(68))); -SHOW_EXPR(int(d2(69))); -SHOW_EXPR(int(d2(70))); -SHOW_EXPR(int(d2(71))); -SHOW_EXPR(int(d2(72))); -SHOW_EXPR(int(d2(73))); -SHOW_EXPR(int(d2(74))); -SHOW_EXPR(int(d2(75))); +// auto d1 = Draw([](Draw& draw, uint cycle, uint){ +// draw.probability(cycle*0.2); +// }); +// +//SHOW_EXPR(int(d1( 0))); +//SHOW_EXPR(int(d1( 1))); +//SHOW_EXPR(int(d1( 2))); +//SHOW_EXPR(int(d1( 16))); +//SHOW_EXPR(int(d1( 32))); +//SHOW_EXPR(int(d1( 48))); +//SHOW_EXPR(int(d1( 63))); +//SHOW_EXPR(int(d1( 64))); +//SHOW_EXPR(int(d1( 64 +1))); +//SHOW_EXPR(int(d1( 64 +2))); +//SHOW_EXPR(int(d1( 64+16))); +//SHOW_EXPR(int(d1( 64+32))); +//SHOW_EXPR(int(d1( 64+48))); +//SHOW_EXPR(int(d1( 64+64))); +//SHOW_EXPR(int(d1(128 +16))); +//SHOW_EXPR(int(d1(128 +32))); +//SHOW_EXPR(int(d1(128 +48))); +//SHOW_EXPR(int(d1(128 +64))); +//SHOW_EXPR(int(d1(128+64+16))); +//SHOW_EXPR(int(d1(128+64+32))); +//SHOW_EXPR(int(d1(128+64+48))); +//SHOW_EXPR(int(d1(128+64+64))); + int yy = 99; + float ff = 88; + auto fuK = std::function{[](float& f, int& i, size_t s) -> double { return f + i + s; }}; + auto& f1 = fuK; + auto f2 = lib::meta::func::applyFirst(f1, ff); + using lib::meta::_Fun; + using Sig1 = _Fun::Sig; + using Sig2 = _Fun::Sig; + yy = 22; + ff = 42; +SHOW_TYPE(Sig1) +SHOW_TYPE(Sig2) +SHOW_EXPR(f1 (ff,yy,33)) +SHOW_EXPR(f2 ( yy,33)) +SHOW_TYPE(decltype(f2 ( yy,33))) +SHOW_TYPE(decltype(f2)) + + fuK = [](float& f, int& i, size_t s) -> double { return f * i * s; }; + +SHOW_EXPR(f1 (ff,yy,33)) +SHOW_EXPR(f2 ( yy,33)) } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 038b71f4c..c0a2c2bca 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -57425,6 +57425,144 @@ + + + + + + + + + + + + + + + + + + + + + +

+ der Rückgabetyp muß explizit deklariert werden — ähnlich wie decltype(auto) — denn es kann sein, daß die zusammengesetzte Funktion eine Referenz liefert +

+ +
+ + + +
+
+
+ + + + + + + + + + + + +

+ ...also eine Funktion, der man andere Funktoren gibt, und diese baut einen manipulierten Funktor. Sowas ist extrem nützlich... +

+ + +
+
+ + + + + + +

+ also die Möglichkeit, Argumente durch Funktions-artige »Binder« zu schließen, die dann aber erst zum Aufruf-Zeitpunkt aktiviert werden. In verallgemeinterter Form könnten das beliebige passende Funktoren sein, die auch weiterhin Argumente benötigen — und es müßte ein neuer Funktionstyp synthetisiert werden (klingt schlimmer als es tatsächlich umzusetzen ist, da wir so viele Tuple-Manipulationsfunktionen haben) +

+ + +
+
+
+ + + + + + + + + + + +

+ warum? weil das leichtgewichtiger und inline-freundlicher ist. Ein λ ist ja erst mal eine anonyme Klasse mit jedweder Storage direkt inline; es läßt sich per Kopie und Verschiebung handhaben. Wer damit Probleme hat, kann sich das resultierende Lambda immer in eine Funktion packen, und den dafür passenden Funktor-Typ sollten wir auch als Metafunktion anbieten. Der Nachteil (oder auch Vorteil) von std::function ist, daß das ein Objekt fester (relativ begrenzter) Größe ist, und notfalls automatisch ein Erweiterungsspeicher auf dem Heap mitgeführt wird. +

+ +
+
+
+ + + + + + + + + + + + + +

+ und zwar +

+
    +
  • + Referenz irgendwo in den sonstigen Argumenten +
  • +
  • + Referenz als das Argument, das gebunden wird (⟶ bleibt eine Referenz) +
  • +
  • + den Funktor selber als Referenz übergeben (⟶ bleibt eine Referenz, man kann die konkrete Funktion austauschen) +
  • +
+ + +
+
+
+ + + + + + +

+ ...das bekannte leidige Problem: argument packs sind keine Typen; man kann sie daher nicht verarbeiten und weitergeben; stattdessen müsen wir einen Typ mit varidadic parameters verwenden, um am Zielort in der Argumentliste dagegen zu matchen. Da lib::meta::_Fun mehr und mehr zum Analyse-Tool für Funktions-artige Entitäten wird, bietet es sich an, diese Metafunktion selber auch als Transporter für Funktionssignaturen zu verwenden +

+ +
+ +
+ + + + + + +
+
+
+
@@ -96688,6 +96826,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ +
@@ -96960,6 +97100,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + @@ -96968,6 +97112,189 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + + + + + +

+ das ist für den aktuellen Use-case unabdingbar +

+ + +
+ + + + + +

+ ...im Gegensatz zu dem ganzen weiteren Schlonz, den ich die letzten Tage eingebaut habe, „weils grad gang“; ich brauche irgende einen Mechanismus, über den ein später hinzukonfigurierter Funktor in Abhängigkeit von aktuellen Parameter-Daten an der Parametrisierung des RandomDraw "drehen" kann... +

+ + +
+
+ + + + + + + + + + + + + +

+ dangling Reference ⟹ CRASH +

+ + +
+ + + + + + + + + + + +
+
+ + + + + + +

+ Lösung-2: er bindet irgendwie eine Referenz darauf +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ das wäre schön sauber — ABER ... +

+ + +
+ + + + + + + + + + + + + + + + + +

+ läuft auf eine partielle Anwendung der Funktion hinaus +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+