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<X>`, 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.
This commit is contained in:
parent
3611bc94ee
commit
fbf7a792a8
7 changed files with 138 additions and 19 deletions
|
|
@ -116,7 +116,7 @@ namespace meta{
|
|||
: std::true_type
|
||||
{
|
||||
using Ret = RET;
|
||||
using Args = Types<ARGS...>;
|
||||
using Args = TySeq<ARGS...>;
|
||||
using Sig = RET(ARGS...);
|
||||
using Functor = std::function<Sig>;
|
||||
enum { ARITY = sizeof...(ARGS) };
|
||||
|
|
@ -343,7 +343,17 @@ namespace meta{
|
|||
template<typename RET, typename ARGS>
|
||||
struct BuildFunType;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future
|
||||
template<typename RET, typename...ARGS>
|
||||
struct BuildFunType<RET, TySeq<ARGS...>>
|
||||
{
|
||||
using Sig = RET(ARGS...);
|
||||
using Fun = _Fun<Sig>;
|
||||
using Func = function<Sig>;
|
||||
using Functor = Func;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisations become obsolete with the old-style type-sequence
|
||||
template< typename RET>
|
||||
struct BuildFunType<RET, Types<> >
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,class,class, uint> class _X_
|
||||
, class TUP
|
||||
, uint i
|
||||
>
|
||||
class BuildTupleAccessor< _X_, TySeq<>, TUP, i>
|
||||
{
|
||||
public:
|
||||
using Product = _X_<NullType, TUP, TUP, i>; // Note: i == tuple size
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////////TICKET #987 : the following specialisation will be obsoleted by the removal of old-style type-sequences
|
||||
template
|
||||
< template<class,class,class, uint> class _X_
|
||||
, class TUP
|
||||
|
|
|
|||
|
|
@ -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<TYPES...> variadic, then replace this by a single variadic template
|
||||
*/
|
||||
template<class T, class TYPES>
|
||||
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<T, TYPES...>;
|
||||
using List = typename Types<T, TYPES...>::List;
|
||||
};
|
||||
|
||||
template<class H, class T>
|
||||
struct TySeq< Node<H,T> >
|
||||
{
|
||||
using List = Node<H,T>;
|
||||
using Seq = typename Prepend< H
|
||||
, typename TySeq<T>::Seq
|
||||
>::Seq;
|
||||
};
|
||||
template<>
|
||||
struct TySeq<NullType>
|
||||
{
|
||||
using List = NullType;
|
||||
using Seq = TySeq<>;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #987 temporary WORKAROUND -- to be obsoleted
|
||||
|
||||
|
||||
|
|
@ -181,15 +197,62 @@ namespace meta {
|
|||
struct StripNullType<Types<NullType, TYPES...>>
|
||||
{
|
||||
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<typename...TYPES>
|
||||
struct StripNullType<TySeq<TYPES...>>
|
||||
{
|
||||
using Seq = TySeq<TYPES...>;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////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<TYPES...> variadic, then replace this by a single variadic template
|
||||
*/
|
||||
template<class TYPES>
|
||||
struct Split;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////TICKET #987 : this specialisation handles the variadic case and will be the only definition in future
|
||||
template<typename T1, typename...TS>
|
||||
struct Split<TySeq<T1,TS...> >
|
||||
{
|
||||
using List = typename TySeq<T1,TS...>::List;
|
||||
|
||||
using Head = T1;
|
||||
using First = TySeq<T1>;
|
||||
using Tail = TySeq<TS...>;
|
||||
|
||||
// for finding the end we need the help of typelist-util.hpp
|
||||
|
||||
using PrefixList = typename SplitLast<List>::List;
|
||||
using TailList = typename Tail::List;
|
||||
|
||||
using Prefix = typename TySeq<PrefixList>::Seq;
|
||||
using End = typename SplitLast<List>::Type;
|
||||
using Last = TySeq<End>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Split<TySeq<>>
|
||||
{
|
||||
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<Types<TYPES...>, i>::Head;
|
||||
};
|
||||
template<typename...TYPES, size_t i>
|
||||
struct Pick<TySeq<TYPES...>, i>
|
||||
{
|
||||
using Type = typename Shifted<TySeq<TYPES...>, i>::Head;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Ret, UICoord>::value,
|
||||
"Allocator function must produce UICoordinates (of the actually allocated UI element)");
|
||||
static_assert (std::is_convertible<FurtherArgs, Types<ARGS...>>::value,
|
||||
static_assert (std::is_convertible<FurtherArgs, TySeq<ARGS...>>::value,
|
||||
"Additional parameters of the allocator function must match the AllocSpec<ARGS> template parameters");
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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<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<class TAR, class BA, class RET, typename...ARGS>
|
||||
struct AcceptArgs<TAR,BA,RET, TySeq<ARGS...> >
|
||||
: BA
|
||||
{
|
||||
RET
|
||||
operator() (ARGS ...args)
|
||||
{
|
||||
return static_cast<TAR*> (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<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<class TAR, class BA, class RET, typename...ARGS>
|
||||
struct AcceptBind<TAR,BA,RET, TySeq<ARGS...> >
|
||||
: BA
|
||||
{
|
||||
RET
|
||||
bind (ARGS ...args)
|
||||
{
|
||||
return static_cast<TAR*> (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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue