Invocation: generalise partial-closure cases

With these additions, all conceivable cases are basically addressed.

Take this as opportunity to investigate how the existing implementation
transports values into the Binder, where they will be stored as data fields.
Notably the mechanism of the `TupleConstructor` / `ElmMapper` indeed
''essentially requires'' to pass the initialisers ''by-reference'',
because otherwise there would be limitations on possible mappings.

This implies that not much can be done for ''perfect forwarding'' of initialisers,
but at least the `BindToArgument` can be simplified to take the value directly.
This commit is contained in:
Fischlurch 2025-02-17 21:18:37 +01:00
parent 0cad2dacc0
commit a5a3d46b6a
8 changed files with 186 additions and 78 deletions

View file

@ -699,9 +699,9 @@ namespace func{
typedef function<ReducedSig> ReducedFunc; typedef function<ReducedSig> ReducedFunc;
static ReducedFunc static ReducedFunc
reduced (SIG& f, Tuple<Types<X>> const& val) reduced (SIG& f, X val)
{ {
Tuple<PreparedArgTypes> params {BuildPreparedArgs(val)}; Tuple<PreparedArgTypes> params {BuildPreparedArgs{std::forward_as_tuple (val)}};
return func::Apply<ARG_CNT>::template bind<ReducedFunc> (f, params); return func::Apply<ARG_CNT>::template bind<ReducedFunc> (f, params);
} }
}; };
@ -897,13 +897,10 @@ namespace func{
template<typename SIG, typename TERM> template<typename SIG, typename TERM>
inline inline
typename _PapE<SIG>::FunType::Functor typename _PapE<SIG>::FunType::Functor
bindLast (SIG& f, TERM const& arg) bindLast (SIG& f, TERM&& arg)
{ {
typedef Types<TERM> ArgTypeSeq;
typedef Tuple<ArgTypeSeq> ArgTuple;
ArgTuple argT(arg);
enum { LAST_POS = -1 + count<typename _Fun<SIG>::Args::List>::value }; enum { LAST_POS = -1 + count<typename _Fun<SIG>::Args::List>::value };
return BindToArgument<SIG,TERM,LAST_POS>::reduced (f, argT); return BindToArgument<SIG,TERM,LAST_POS>::reduced (f, std::forward<TERM> (arg));
} }

View file

@ -1,5 +1,5 @@
/* /*
TUPLE-CLOSURE.hpp - metaprogramming tools for closing a function over given arguments TUPLE-CLOSURE.hpp - metaprogramming tools for tuple-likes with partial closure
Copyright (C) Copyright (C)
2025, Hermann Vosseler <Ichthyostega@web.de> 2025, Hermann Vosseler <Ichthyostega@web.de>
@ -49,6 +49,12 @@
namespace lib { namespace lib {
namespace meta{ namespace meta{
/**
* Metaprogramming helper to build a constructor-function
* for »tuple-like« records, where some of the initialisation
* values are immediately closed (≙ fixed), while the remaining
* ones are supplied as function arguments.
*/
template<class PAR> template<class PAR>
struct TupleClosureBuilder; struct TupleClosureBuilder;
@ -59,9 +65,9 @@ namespace meta{
using TupleBuilderSig = Tuple(PARS...); using TupleBuilderSig = Tuple(PARS...);
static Tuple static Tuple
buildParam (PARS ...params) buildRecord (PARS ...params)
{ {
return {params...}; return {std::move(params)...};
} }
template<typename...VALS> template<typename...VALS>
@ -69,7 +75,7 @@ namespace meta{
closeFront (VALS ...vs) closeFront (VALS ...vs)
{ {
using ClosedTypes = TySeq<VALS...>; using ClosedTypes = TySeq<VALS...>;
return wrapBuilder (func::PApply<TupleBuilderSig, ClosedTypes>::bindFront (buildParam, std::make_tuple(vs...))); return wrapBuilder (func::PApply<TupleBuilderSig, ClosedTypes>::bindFront (buildRecord, std::make_tuple(vs...)));
} }
template<typename...VALS> template<typename...VALS>
@ -77,7 +83,14 @@ namespace meta{
closeBack (VALS ...vs) closeBack (VALS ...vs)
{ {
using ClosedTypes = TySeq<VALS...>; using ClosedTypes = TySeq<VALS...>;
return wrapBuilder (func::PApply<TupleBuilderSig, ClosedTypes>::bindBack (buildParam, std::make_tuple(vs...))); return wrapBuilder (func::PApply<TupleBuilderSig, ClosedTypes>::bindBack (buildRecord, std::make_tuple(vs...)));
}
template<size_t idx, typename VAL>
static auto
close (VAL val)
{
return wrapBuilder (func::BindToArgument<TupleBuilderSig,VAL,idx>::reduced (buildRecord, val));
} }
private: private:
@ -97,39 +110,33 @@ namespace meta{
}; };
/* ===== adapt array for tuple-like signature ===== */ /* ===== adapt array for tuple-like signature ===== */
/**
* Metaprogramming adapter to overlay a tuple-like signature
* on top of std::array, with N times the same type.
*/
template<typename...TTT> template<typename...TTT>
struct ArrayAdapt; struct ArrayAdapt;
/** Metafunction to detect if a type-sequence holds uniform types */
template<typename...TTT>
struct AllSame
: std::true_type // trivially true for empty conjunction and single element
{ };
template<typename T1, typename T2, typename...TS>
struct AllSame<T1,T2,TS...>
: __and_<is_same<T1,T2>
,AllSame<T2,TS...>
>
{ };
namespace { namespace {
/** Type constructor */
template<typename...TTT>
struct AllSame
: std::true_type
{ };
template<typename T1, typename T2, typename...TS>
struct AllSame<T1,T2,TS...>
: __and_<is_same<T1,T2>
,AllSame<T2,TS...>
>
{ };
template<typename T, size_t N>
struct Repeat
{
using Rem = typename Repeat<T, N-1>::Seq;
using Seq = typename Prepend<T,Rem>::Seq;
};
template<typename T>
struct Repeat<T,0>
{
using Seq = TySeq<>;
};
template<typename T, size_t N> template<typename T, size_t N>
struct _Adapt struct _Adapt
{ {
@ -141,6 +148,7 @@ namespace meta{
using _AdaptArray_t = typename _Adapt<T,N>::Array; using _AdaptArray_t = typename _Adapt<T,N>::Array;
} }
/** @note adding seamless conversion and compount-init */
template<typename T, typename...TT> template<typename T, typename...TT>
struct ArrayAdapt<T,TT...> struct ArrayAdapt<T,TT...>
: std::array<T, 1+sizeof...(TT)> : std::array<T, 1+sizeof...(TT)>
@ -149,6 +157,7 @@ namespace meta{
,"Array can only hold elements of uniform type"); ,"Array can only hold elements of uniform type");
using Array = std::array<T, 1+sizeof...(TT)>; using Array = std::array<T, 1+sizeof...(TT)>;
ArrayAdapt (Array const& o) : Array{o} { } ArrayAdapt (Array const& o) : Array{o} { }
ArrayAdapt (Array && r) : Array{move(r)} { } ArrayAdapt (Array && r) : Array{move(r)} { }
@ -158,6 +167,11 @@ namespace meta{
{ } { }
}; };
/** partial specialisation to handle a std::array.
* @note the expected input on partially closures
* is then also an array, with fewer elements.
*/
template<typename T, size_t N> template<typename T, size_t N>
struct TupleClosureBuilder<std::array<T,N>> struct TupleClosureBuilder<std::array<T,N>>
: TupleClosureBuilder<_AdaptArray_t<T,N>> : TupleClosureBuilder<_AdaptArray_t<T,N>>
@ -182,6 +196,6 @@ namespace std { // Specialisation to support C++ »Tuple Protocol« and structur
: tuple_element<I, typename lib::meta::ArrayAdapt<TTT...>::Array> : tuple_element<I, typename lib::meta::ArrayAdapt<TTT...>::Array>
{ }; { };
// Note: the std::get<i> function will pick the subclass // Note: the std::get<i> function will pick the baseclass anyway
} }
#endif /*LIB_META_TUPLE_CLOSURE_H*/ #endif /*LIB_META_TUPLE_CLOSURE_H*/

View file

@ -225,11 +225,12 @@ namespace meta {
* - the actual index position of the tuple element * - the actual index position of the tuple element
* to be initialised through this concrete instantiation. * to be initialised through this concrete instantiation.
* @remarks this design has several extension points. Pretty much any conceivable * @remarks this design has several extension points. Pretty much any conceivable
* initialisation logic can be embodied in the `_ElmMapper_` template. The sole * initialisation logic can be embodied in the `_ElmMapper_` template.
* requirement is that the concrete instance is _assignable_ by the source type * Required is that the concrete instance is _constructible_ from the source type
* and _convertible_ to the individual member type of the target tuple it is * and _convertible_ to the individual member type of the target tuple it is
* invoked for. Moreover, it is possible to build a generic _element extractor_, * invoked for. Source data _must_ be taken by-value, from the ctor argument.
* which will be specialised on base of the source type accepted. * @note based on this mechanics, a generic _element extractor_ may be built,
* selecting a (partial) specialisation based on the source type given.
* @see ExtractArg * @see ExtractArg
*/ */
template< typename TYPES template< typename TYPES
@ -243,15 +244,15 @@ namespace meta {
protected: protected:
template<class SRC, size_t...idx> template<class SRC, size_t...idx>
TupleConstructor (SRC values, IndexSeq<idx...>) TupleConstructor (SRC initVals, IndexSeq<idx...>)
: Tuple<TYPES> (_ElmMapper_<SRC, Tuple<TYPES>, idx>{values}...) : Tuple<TYPES> (_ElmMapper_<SRC, Tuple<TYPES>, idx>{initVals}...)
{ } { }
public: public:
template<class SRC> template<class SRC>
TupleConstructor (SRC values) TupleConstructor (SRC values)
: TupleConstructor (values, SequenceIterator()) : TupleConstructor (std::move(values), SequenceIterator())
{ } { }
}; };

View file

@ -80,9 +80,9 @@ namespace meta {
} }
/** /**
* Helper: prepend a type to an existing type sequence, * Helper: prepend a type to an existing type sequence,
* thus shifting all elements within the sequence * thus shifting all elements within the sequence
* to the right, eventually dropping the last element * to the right, eventually dropping the last element
* @todo support variadic type-seq ////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types<TYPES...> variadic, then replace this by a single variadic template * @todo support variadic type-seq ////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types<TYPES...> variadic, then replace this by a single variadic template
*/ */
@ -128,9 +128,9 @@ namespace meta {
/** /**
* Additional specialisation of the basic type sequence type, * Additional specialisation of the basic type sequence type,
* allowing to re-create a (flat) type sequence from a typelist. * allowing to re-create a (flat) type sequence from a typelist.
*/ */
template<class H, class T> template<class H, class T>
struct Types< Node<H,T> > struct Types< Node<H,T> >
@ -280,7 +280,7 @@ namespace meta {
, T16,T17,T18,T19,T20 , T16,T17,T18,T19,T20
> > > >
{ {
typedef typename typedef typename
Types< T01,T02,T03,T04,T05 Types< T01,T02,T03,T04,T05
, T06,T07,T08,T09,T10 , T06,T07,T08,T09,T10
, T11,T12,T13,T14,T15 , T11,T12,T13,T14,T15
@ -308,9 +308,9 @@ namespace meta {
/** /**
* Helper: generate a type sequence left shifted * Helper: generate a type sequence left shifted
* by i steps, filling in NullType at the end * by i steps, filling in NullType at the end
*/ */
template<class TYPES, uint i=1> template<class TYPES, uint i=1>
class Shifted class Shifted
{ {
@ -322,14 +322,14 @@ namespace meta {
template<class TYPES> template<class TYPES>
struct Shifted<TYPES,0> struct Shifted<TYPES,0>
{ {
typedef TYPES Type; typedef TYPES Type;
typedef typename Split<Type>::Head Head; typedef typename Split<Type>::Head Head;
}; };
/** /**
* specialisation: pick n-th element from a type sequence * specialisation: pick n-th element from a type sequence
* @see typelist-manip.hpp * @see typelist-manip.hpp
*/ */
@ -346,6 +346,23 @@ namespace meta {
/**
* Generate a type-sequence filled with
* \a N times the same type \a T
*/
template<typename T, size_t N>
struct Repeat
{
using Rem = typename Repeat<T, N-1>::Seq;
using Seq = typename Prepend<T,Rem>::Seq;
};
template<typename T>
struct Repeat<T,0>
{
using Seq = TySeq<>;
};
}} // namespace lib::meta }} // namespace lib::meta

View file

@ -206,9 +206,10 @@ namespace test {
void void
build_Node_closedParam() build_Node_closedParam()
{ {
using Params = std::tuple<uint,uint,uint,uint,uint>;//array<uint, 5>; using Params = array<uint, 5>;
auto procFun = [](Params params, uint* out) { auto [v1,v2,v3,v4,v5] = params; *out = v1+v2+v3+v4+v5; };//explore(params).resultSum(); }; auto procFun = [](Params params, uint* out){ *out = explore(params).resultSum(); };
auto autoFun = [](Time nomTime){ return FrameNr::quant (nomTime, SECONDS_GRID); }; auto autoFun = [](Time nomTime){ return uint(FrameNr::quant (nomTime, SECONDS_GRID));};
ProcNode node{prepareNode("Test") ProcNode node{prepareNode("Test")
.preparePort() .preparePort()
.invoke ("fun()", procFun) .invoke ("fun()", procFun)

View file

@ -342,13 +342,12 @@ namespace test {
Sig15& f = fun15<1,2,3,4,5>; Sig15& f = fun15<1,2,3,4,5>;
SigA5& f5 = fun11<5>; SigA5& f5 = fun11<5>;
Tuple<Types<char>> argT(55);
function<SigR1> f_bound_1 = BindToArgument<Sig15,char,0>::reduced (f, argT); function<SigR1> f_bound_1 = BindToArgument<Sig15,char,0>::reduced (f, 55);
function<SigR2> f_bound_2 = BindToArgument<Sig15,char,1>::reduced (f, argT); function<SigR2> f_bound_2 = BindToArgument<Sig15,char,1>::reduced (f, 55);
function<SigR3> f_bound_3 = BindToArgument<Sig15,char,2>::reduced (f, argT); function<SigR3> f_bound_3 = BindToArgument<Sig15,char,2>::reduced (f, 55);
function<SigR4> f_bound_4 = BindToArgument<Sig15,char,3>::reduced (f, argT); function<SigR4> f_bound_4 = BindToArgument<Sig15,char,3>::reduced (f, 55);
function<SigR5> f_bound_5 = BindToArgument<Sig15,char,4>::reduced (f, argT); function<SigR5> f_bound_5 = BindToArgument<Sig15,char,4>::reduced (f, 55);
CHECK (55+2+3+4+5 == f_bound_1 ( _2_,_3_,_4_,_5_) ); CHECK (55+2+3+4+5 == f_bound_1 ( _2_,_3_,_4_,_5_) );
CHECK (1+55+3+4+5 == f_bound_2 (_1_, _3_,_4_,_5_) ); CHECK (1+55+3+4+5 == f_bound_2 (_1_, _3_,_4_,_5_) );
@ -359,7 +358,7 @@ namespace test {
// degenerate case: specify wrong argument position (behind end of argument list) // degenerate case: specify wrong argument position (behind end of argument list)
// causes the argument to be simply ignored and no binding to happen // causes the argument to be simply ignored and no binding to happen
function<Sig15> f_bound_X = BindToArgument<Sig15,char,5>::reduced (f, argT); function<Sig15> f_bound_X = BindToArgument<Sig15,char,5>::reduced (f, 88);
CHECK (1+2+3+4+5 == f_bound_X (_1_,_2_,_3_,_4_,_5_) ); CHECK (1+2+3+4+5 == f_bound_X (_1_,_2_,_3_,_4_,_5_) );

View file

@ -55,6 +55,7 @@ namespace test {
{ {
tuple_bindFront(); tuple_bindFront();
tuple_bindBack(); tuple_bindBack();
tuple_bindArg();
array_bindFront(); array_bindFront();
} }
@ -69,8 +70,7 @@ namespace test {
auto cons = Builder::closeFront (1,2.3); auto cons = Builder::closeFront (1,2.3);
using FunType = _Fun<decltype(cons)>; using FunType = _Fun<decltype(cons)>;
CHECK (FunType()); CHECK (FunType() == true); // indeed a function
SHOW_EXPR(showType<FunType::Sig>())
CHECK (showType<FunType::Sig>() == "tuple<int, double, string> (tuple<string>)"_expect); CHECK (showType<FunType::Sig>() == "tuple<int, double, string> (tuple<string>)"_expect);
Tup tup = cons("five"); Tup tup = cons("five");
@ -99,6 +99,26 @@ SHOW_EXPR(showType<FunType::Sig>())
} }
/** @test fix specific argument within tuple
*/
void
tuple_bindArg()
{
using Tup = tuple<int,double,string>;
using Builder = TupleClosureBuilder<Tup>;
auto c1 = Builder::close<1>(3.1415927);
CHECK (showType<_Fun<decltype(c1)>::Sig>() == "tuple<int, double, string> (tuple<int, string>)"_expect);
Tup t1 = c1({2,"π"});
CHECK (t1 == "«tuple<int, double, string>»──(2,3.1415927,π)"_expect);
auto c2 = Builder::close<3>("fantastic");
// Binding to out-of-scope arguments is ignored: the result is the identity-function
CHECK (showType<_Fun<decltype(c2)>::Sig>() == "tuple<int, double, string> (tuple<int, double, string>)"_expect);
}
/** @test use a std::array and handle it like a tuple to pre-fix some elements /** @test use a std::array and handle it like a tuple to pre-fix some elements
*/ */
void void

View file

@ -106027,12 +106027,65 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node COLOR="#338800" CREATED="1739752776321" ID="ID_376565948" MODIFIED="1739752785816" TEXT="TupleClosure_test zur Dokumentation"> <node COLOR="#338800" CREATED="1739752776321" ID="ID_376565948" MODIFIED="1739752785816" TEXT="TupleClosure_test zur Dokumentation">
<icon BUILTIN="button_ok"/> <icon BUILTIN="button_ok"/>
</node> </node>
<node COLOR="#338800" CREATED="1739822405519" ID="ID_1159986625" MODIFIED="1739822418374" TEXT="weitere partial-closure-F&#xe4;lle integrieren">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1739822430227" ID="ID_1498733913" MODIFIED="1739822453922">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
wie steht's mit <i>perfect forwarding</i>?
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
<node CREATED="1739822460457" ID="ID_813032583" MODIFIED="1739822493962">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
ohnehin limitiert: wir konstruieren stets Werte <i>in den Binder</i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#5b280f" CREATED="1739822514329" ID="ID_304319384" MODIFIED="1739822915159" TEXT="TupleConstructor?">
<icon BUILTIN="help"/>
<icon BUILTIN="button_cancel"/>
<node CREATED="1739822603555" ID="ID_1985055743" MODIFIED="1739822681557" TEXT="er nimmt ein Argument-Tupel per Value"/>
<node CREATED="1739822682873" ID="ID_76296788" MODIFIED="1739822813779" TEXT="dessen Inhalt wird per Referenz durch den ElmMapper durchgereicht"/>
<node CREATED="1739822742383" ID="ID_1631025117" MODIFIED="1739822805415" TEXT="das ist hier sogar ein essentielles Feature">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn nur auf diesem Weg hat der ElmMapper die komplette Freiheit und kann im Besonderen Werte selbst konstruieren, oder aber auch Werte mehrfach mappen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1739822955768" ID="ID_82653424" MODIFIED="1739822974789" TEXT="wir k&#xf6;nnen also nur Werte bis zum Tuple-Constructor bringen"/>
<node CREATED="1739822976729" ID="ID_539739884" MODIFIED="1739822995033" TEXT="aber: BindToArgument k&#xf6;nnte einen einfachen Wert nehmen"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739756728914" ID="ID_1671606956" MODIFIED="1739813490672" TEXT="Auf std::array anwendbar machen"> <node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739756728914" ID="ID_1671606956" MODIFIED="1739813490672" TEXT="Auf std::array anwendbar machen">
<icon BUILTIN="pencil"/> <icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739756741667" ID="ID_20824263" MODIFIED="1739813448142" TEXT="Problem: spezielle Typsignatur"> <node COLOR="#338800" CREATED="1739756741667" ID="ID_20824263" MODIFIED="1739816589487" TEXT="Problem: spezielle Typsignatur">
<icon BUILTIN="pencil"/> <icon BUILTIN="button_ok"/>
<node CREATED="1739756760373" ID="ID_753184722" MODIFIED="1739756775186" TEXT="deshalb ist in jedem Fall eine partielle Spezialisierung notwendig"/> <node CREATED="1739756760373" ID="ID_753184722" MODIFIED="1739756775186" TEXT="deshalb ist in jedem Fall eine partielle Spezialisierung notwendig"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1739756922215" ID="ID_1294911921" MODIFIED="1739798944791" TEXT="Problem: eine Builder-Funktion mit expliziter Argument-Anzahl"> <node BACKGROUND_COLOR="#edc89e" COLOR="#690f14" CREATED="1739756922215" ID="ID_1294911921" MODIFIED="1739816544790" TEXT="Problem: eine Builder-Funktion mit expliziter Argument-Anzahl">
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
<node CREATED="1739756977184" ID="ID_1621203501" MODIFIED="1739757006679" TEXT="den Signatur-Typ k&#xf6;nnte man noch leicht synthetisieren"> <node CREATED="1739756977184" ID="ID_1621203501" MODIFIED="1739757006679" TEXT="den Signatur-Typ k&#xf6;nnte man noch leicht synthetisieren">
<richcontent TYPE="NOTE"><html> <richcontent TYPE="NOTE"><html>
@ -106049,16 +106102,24 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<icon BUILTIN="button_cancel"/> <icon BUILTIN="button_cancel"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1739798967457" ID="ID_1274106457" MODIFIED="1739813473419" TEXT="anderer Ansatz: Tupel-Typsignatur emulieren"> <node BACKGROUND_COLOR="#e3dfc5" COLOR="#435e98" CREATED="1739798967457" ID="ID_1274106457" MODIFIED="1739816566683" TEXT="anderer Ansatz: Tupel-Typsignatur emulieren">
<icon BUILTIN="idea"/> <icon BUILTIN="idea"/>
<node CREATED="1739798985823" ID="ID_9547449" MODIFIED="1739799013054" TEXT="...dann k&#xf6;nnte die Standard-Impl verwendet werden"/> <node CREATED="1739798985823" ID="ID_9547449" MODIFIED="1739799013054" TEXT="...dann k&#xf6;nnte die Standard-Impl verwendet werden"/>
<node CREATED="1739799014639" ID="ID_205042889" MODIFIED="1739799031581" TEXT="brauche daf&#xfc;r einen automatisch konvertierbaren Adapter"/> <node COLOR="#435e98" CREATED="1739799014639" ID="ID_205042889" MODIFIED="1739816580797" TEXT="brauche daf&#xfc;r einen automatisch konvertierbaren Adapter">
<node CREATED="1739807307000" ID="ID_382558613" MODIFIED="1739812304265" TEXT="mu&#xdf; dann wohl Tuple-Protocol reimplementieren"> <icon BUILTIN="yes"/>
</node>
<node COLOR="#435e98" CREATED="1739807307000" ID="ID_382558613" MODIFIED="1739816571751" TEXT="mu&#xdf; dann wohl Tuple-Protocol reimplementieren">
<arrowlink COLOR="#846867" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-1112;-50;" ID="Arrow_ID_577510339" STARTARROW="None" STARTINCLINATION="-1320;72;"/> <arrowlink COLOR="#846867" DESTINATION="ID_872833596" ENDARROW="Default" ENDINCLINATION="-1112;-50;" ID="Arrow_ID_577510339" STARTARROW="None" STARTINCLINATION="-1320;72;"/>
<icon BUILTIN="smiley-oh"/> <icon BUILTIN="smiley-oh"/>
</node> </node>
</node> </node>
</node> </node>
<node COLOR="#338800" CREATED="1739816632434" ID="ID_1046144111" MODIFIED="1739816647386" TEXT="Aggregat-Initialisierung erm&#xf6;glichen">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1739816653616" ID="ID_1737045068" MODIFIED="1739816676602" TEXT="Tuple-Protocol wird unterst&#xfc;tzt">
<icon BUILTIN="flag-pink"/>
</node>
</node> </node>
</node> </node>
</node> </node>
@ -154631,8 +154692,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
Angenommen, wir haben eine Klasse, die aus std::tuple ableitet. Man w&#252;rde sich w&#252;nschen, diese w&#252;rde automatisch am Tuple-Protocol partizipieren. Tut sie aber nicht, weil schon die Spezialisierung von std::tuple_size nicht greift. Das ist aber auch gut so, denn sonst w&#228;re man auf die Implementierung von std::tuple festgelegt, und k&#246;nnte z.B. keine Anpassungen am Storage-Management machen. Wenn man <i>so etwas m&#246;chte, dann sollte man die klassische-OO verwenden.</i> Angenommen, wir haben eine Klasse, die aus std::tuple ableitet. Man w&#252;rde sich w&#252;nschen, diese w&#252;rde automatisch am Tuple-Protocol partizipieren. Tut sie aber nicht, weil schon die Spezialisierung von std::tuple_size nicht greift. Das ist aber auch gut so, denn sonst w&#228;re man auf die Implementierung von std::tuple festgelegt, und k&#246;nnte z.B. keine Anpassungen am Storage-Management machen. Wenn man <i>so etwas m&#246;chte, dann sollte man die klassische-OO verwenden.</i>
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1739807542287" ID="ID_1950397403" MODIFIED="1739807563117" TEXT="Vorsicht Falle: Funktion-Overloads beachten die Basisklasse"> <node CREATED="1739807542287" ID="ID_1950397403" MODIFIED="1739807563117" TEXT="Vorsicht Falle: Funktion-Overloads beachten die Basisklasse">
<icon BUILTIN="messagebox_warning"/> <icon BUILTIN="messagebox_warning"/>
@ -154684,8 +154744,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
ABER nur wenn der Template-Parameter <b>f&#252;r diesen konkreten Aufruf</b>&#160; instantiiert wird; ein Typ-Parameter einer umschlie&#223;enden Klasse gilt bereits als fest gebunden, also <i>funktioniert mit damit kein &#187;perfect forwarding&#171;.</i>&#160;Im Besonderen bei Konstruktoren ist das eine h&#228;ufig anzutreffende Falle ABER nur wenn der Template-Parameter <b>f&#252;r diesen konkreten Aufruf</b>&#160; instantiiert wird; ein Typ-Parameter einer umschlie&#223;enden Klasse gilt bereits als fest gebunden, also <i>funktioniert mit damit kein &#187;perfect forwarding&#171;.</i>&#160;Im Besonderen bei Konstruktoren ist das eine h&#228;ufig anzutreffende Falle
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </node>
<node CREATED="1739804952757" ID="ID_996711039" MODIFIED="1739804967987" TEXT="es ist und bleibt ein Compilerbau-Trick"> <node CREATED="1739804952757" ID="ID_996711039" MODIFIED="1739804967987" TEXT="es ist und bleibt ein Compilerbau-Trick">
<icon BUILTIN="smiley-angry"/> <icon BUILTIN="smiley-angry"/>