From fbf7a792a87404f8b180af044ad2d5e18742978d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 16 Feb 2025 21:10:06 +0100 Subject: [PATCH] Library: a step towards variadic type sequences (see #987) Likely the most widely used facility, which enters into meta-programming with type sequences, is our function-signature-detector `_Fun`, which returns a argument type-sequence. After adding some bridges for cross-compatibility, function-arguments are now extracted as a new-style, ''variadic sequence'' without trailing `NullType`. Doing so required to augment some of the most widely used sequence-processing helpers to work seamlessly also with the new-style variadic sequences with a definition variant based on variadics, which typically will later-on obsolete the original solution, which at that time needed to be tediously coded as a series of explicit specialisations for N arguments. --- src/lib/meta/function.hpp | 12 +++- src/lib/meta/tuple-helper.hpp | 12 ++++ src/lib/meta/typeseq-util.hpp | 72 ++++++++++++++++++++- src/stage/interact/view-spec-dsl.hpp | 4 +- src/steam/control/argument-tuple-accept.hpp | 31 ++++++++- tests/library/scoped-collection-test.cpp | 2 +- tests/library/test/test-tracking-test.cpp | 24 +++---- 7 files changed, 138 insertions(+), 19 deletions(-) diff --git a/src/lib/meta/function.hpp b/src/lib/meta/function.hpp index a6df90aa3..eb8821d28 100644 --- a/src/lib/meta/function.hpp +++ b/src/lib/meta/function.hpp @@ -116,7 +116,7 @@ namespace meta{ : std::true_type { using Ret = RET; - using Args = Types; + using Args = TySeq; using Sig = RET(ARGS...); using Functor = std::function; enum { ARITY = sizeof...(ARGS) }; @@ -343,7 +343,17 @@ namespace meta{ template struct BuildFunType; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future + template + struct BuildFunType> + { + using Sig = RET(ARGS...); + using Fun = _Fun; + using Func = function; + using Functor = Func; + }; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisations become obsolete with the old-style type-sequence template< typename RET> struct BuildFunType > { diff --git a/src/lib/meta/tuple-helper.hpp b/src/lib/meta/tuple-helper.hpp index 4ec4b1120..02b32993d 100644 --- a/src/lib/meta/tuple-helper.hpp +++ b/src/lib/meta/tuple-helper.hpp @@ -338,6 +338,18 @@ namespace meta { }; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future + template + < template class _X_ + , class TUP + , uint i + > + class BuildTupleAccessor< _X_, TySeq<>, TUP, i> + { + public: + using Product = _X_; // Note: i == tuple size + }; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisation will be obsoleted by the removal of old-style type-sequences template < template class _X_ , class TUP diff --git a/src/lib/meta/typeseq-util.hpp b/src/lib/meta/typeseq-util.hpp index d3e30d14e..d8a8af1e4 100644 --- a/src/lib/meta/typeseq-util.hpp +++ b/src/lib/meta/typeseq-util.hpp @@ -84,10 +84,11 @@ namespace meta { * Helper: prepend a type to an existing type sequence, * thus shifting all elements within the sequence * to the right, eventually dropping the last element + * @todo support variadic type-seq ////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types variadic, then replace this by a single variadic template */ template struct Prepend; - + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisation will be obsoleted by the removal of old-style type-sequences template< typename T01 , typename T02 , typename T03 @@ -155,6 +156,21 @@ namespace meta { using Seq = TySeq; using List = typename Types::List; }; + + template + struct TySeq< Node > + { + using List = Node; + using Seq = typename Prepend< H + , typename TySeq::Seq + >::Seq; + }; + template<> + struct TySeq + { + using List = NullType; + using Seq = TySeq<>; + }; //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #987 temporary WORKAROUND -- to be obsoleted @@ -181,15 +197,62 @@ namespace meta { struct StripNullType> { using Seq = TySeq<>; // NOTE: this causes the result to be a TySeq + }; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisation is a catch-all and becomes obsolete + template + struct StripNullType> + { + using Seq = TySeq; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #987 temporary WORKAROUND(End) -- to be obsoleted - /** Helper: separate parts of a type sequence */ + /** Helper: separate parts of a type sequence + * @todo support variadic type-seq ////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types variadic, then replace this by a single variadic template + */ template struct Split; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future + template + struct Split > + { + using List = typename TySeq::List; + + using Head = T1; + using First = TySeq; + using Tail = TySeq; + + // for finding the end we need the help of typelist-util.hpp + + using PrefixList = typename SplitLast::List; + using TailList = typename Tail::List; + + using Prefix = typename TySeq::Seq; + using End = typename SplitLast::Type; + using Last = TySeq; + }; + + template<> + struct Split> + { + using List = NullType; + + using Head = NullType; + using First = TySeq<>; + using Tail = TySeq<>; + + // for finding the end we need the help of typelist-util.hpp + + using PrefixList = NullType; + using TailList = NullType; + + using Prefix = TySeq<>; + using Last = TySeq<>; + using End = NullType; + }; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisation will be obsoleted by the removal of old-style type-sequences template< typename T01 , typename T02 , typename T03 @@ -275,6 +338,11 @@ namespace meta { { using Type = typename lib::meta::Shifted, i>::Head; }; + template + struct Pick, i> + { + using Type = typename Shifted, i>::Head; + }; diff --git a/src/stage/interact/view-spec-dsl.hpp b/src/stage/interact/view-spec-dsl.hpp index f1d48dcb6..cff61f329 100644 --- a/src/stage/interact/view-spec-dsl.hpp +++ b/src/stage/interact/view-spec-dsl.hpp @@ -207,7 +207,7 @@ namespace interact { using lib::meta::_Fun; using lib::meta::Split; using lib::meta::Tuple; - using lib::meta::Types; + using lib::meta::TySeq; using lib::meta::func::_Sig; using lib::meta::func::PApply; @@ -220,7 +220,7 @@ namespace interact { "Allocator function must accept UICoordinates (where to create/locate) as first argument"); static_assert (std::is_convertible::value, "Allocator function must produce UICoordinates (of the actually allocated UI element)"); - static_assert (std::is_convertible>::value, + static_assert (std::is_convertible>::value, "Additional parameters of the allocator function must match the AllocSpec template parameters"); diff --git a/src/steam/control/argument-tuple-accept.hpp b/src/steam/control/argument-tuple-accept.hpp index 697050a3d..55680cdc7 100644 --- a/src/steam/control/argument-tuple-accept.hpp +++ b/src/steam/control/argument-tuple-accept.hpp @@ -71,13 +71,28 @@ namespace control { // // _______________________________________________________________________________________________________________ - /** @internal mix in a function operator */ + /** @internal mix in a function operator + * @todo variadic type-seq //////////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types variadic, then replace this by a single variadic template + */ template< class TAR, class BA, class RET , typename TYPES > struct AcceptArgs ; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future + template + struct AcceptArgs > + : BA + { + RET + operator() (ARGS ...args) + { + return static_cast (this) -> bindArg (make_tuple (std::move(args) ...)); + } + }; + + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisations become obsolete with the old-style type-sequence /* specialisations for 0...9 Arguments.... */ template< class TAR, class BA, class RET @@ -262,13 +277,27 @@ namespace control { // // _______________________________________________________________________________________________________________ /** @internal mix in a \c bind() function + * @todo variadic type-seq //////////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types variadic, then replace this by a single variadic template */ template< class TAR, class BA, class RET , typename TYPES > struct AcceptBind ; + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future + template + struct AcceptBind > + : BA + { + RET + bind (ARGS ...args) + { + return static_cast (this) -> bindArg (make_tuple (std::move(args)...)); + } + }; + + ///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisations become obsolete with the old-style type-sequence /* specialisations for 0...9 Arguments.... */ template< class TAR, class BA, class RET diff --git a/tests/library/scoped-collection-test.cpp b/tests/library/scoped-collection-test.cpp index b3126e182..7d84c357b 100644 --- a/tests/library/scoped-collection-test.cpp +++ b/tests/library/scoped-collection-test.cpp @@ -270,7 +270,7 @@ namespace test{ CHECK (d0.calc(0) == 11 + 22); // The others even point into obsoleted storage holding zombie objects - CHECK (d1.calc(44) == rr + 44); + CHECK (d1.getVal() == Dummy::DEAD); } CHECK (0 == Dummy::checksum()); diff --git a/tests/library/test/test-tracking-test.cpp b/tests/library/test/test-tracking-test.cpp index a1fcf92d5..ede13577e 100644 --- a/tests/library/test/test-tracking-test.cpp +++ b/tests/library/test/test-tracking-test.cpp @@ -118,21 +118,21 @@ namespace test{ CHECK (Dummy::checksum() == dum1.getVal()); Dummy dum2{55}; - CHECK (55 == dum2.getVal()); + CHECK (dum2.getVal() == 55); CHECK (Dummy::checksum() == dum1.getVal() + 55); Dummy dum3{move (dum2)}; - CHECK (55 == dum3.getVal()); - CHECK (0 == dum2.getVal()); + CHECK (dum3.getVal() == 55); + CHECK (dum2.getVal() == Dummy::DEFUNCT); dum3.setVal (23); - CHECK (23 == dum3.getVal()); + CHECK (dum3.getVal() == 23); dum1 = move (dum3); - CHECK (23 == dum1.getVal()); - CHECK (0 == dum2.getVal()); - CHECK (0 == dum3.getVal()); - CHECK (Dummy::checksum() == 23); + CHECK (dum1.getVal() == 23 ); + CHECK (dum2.getVal() == Dummy::DEFUNCT); + CHECK (dum3.getVal() == Dummy::DEFUNCT); + CHECK (Dummy::checksum() == 23 ); Dummy::activateCtorFailure (true); try { @@ -145,10 +145,10 @@ namespace test{ Dummy::checksum() -= v; } Dummy::activateCtorFailure (false); - CHECK (23 == dum1.getVal()); - CHECK (0 == dum2.getVal()); - CHECK (0 == dum3.getVal()); - CHECK (Dummy::checksum() == 23); + CHECK (dum1.getVal() == 23 ); + CHECK (dum2.getVal() == Dummy::DEFUNCT); + CHECK (dum3.getVal() == Dummy::DEFUNCT); + CHECK (Dummy::checksum() == 23 ); } CHECK (Dummy::checksum() == 0); }