Metaprogramming: extend testcase and remould pickInit to support arbitrary arguments
as it turned out, the solution from yesterday works only with uniform argument lists, but not with arbitrarily mixed types. Moreover the whole trickery with the indices was shitty -- better use a predicate decision on template argument level. This simple solution somehow just didn't occur to me...
This commit is contained in:
parent
636ab6e608
commit
4348cd462c
2 changed files with 81 additions and 26 deletions
|
|
@ -150,6 +150,9 @@ namespace meta {
|
|||
{
|
||||
template<size_t i>
|
||||
using AppendElm = IndexSeq<idx..., i>;
|
||||
|
||||
template<size_t i>
|
||||
using PrependElm = IndexSeq<i, idx...>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -159,10 +162,11 @@ namespace meta {
|
|||
template<size_t n>
|
||||
struct BuildIndexSeq
|
||||
{
|
||||
using Ascending = typename BuildIndexSeq<n-1>::Ascending::template AppendElm<n-1>;
|
||||
using Ascending = typename BuildIndexSeq<n-1>::Ascending::template AppendElm<n-1>;
|
||||
using Descending = typename BuildIndexSeq<n-1>::Descending::template PrependElm<n-1>;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename BuildIndexSeq<n-1>::template OffsetBy<d>::template AppendElm<n-1+d>;
|
||||
using OffsetBy = typename BuildIndexSeq<n-1>::template OffsetBy<d>::template AppendElm<n-1+d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename BuildIndexSeq<n-1>::template FilledWith<x>::template AppendElm<x>;
|
||||
|
|
@ -179,10 +183,11 @@ namespace meta {
|
|||
{
|
||||
using Empty = IndexSeq<>;
|
||||
|
||||
using Ascending = Empty;
|
||||
using Ascending = Empty;
|
||||
using Descending = Empty;
|
||||
|
||||
template<size_t>
|
||||
using OffsetBy = Empty;
|
||||
using OffsetBy = Empty;
|
||||
|
||||
template<size_t>
|
||||
using FilledWith = Empty;
|
||||
|
|
@ -205,10 +210,11 @@ namespace meta {
|
|||
enum {SIZ = sizeof...(TYPES) };
|
||||
using Builder = BuildIndexSeq<SIZ>;
|
||||
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Descending = typename Builder::Descending;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename Builder::template FilledWith<x>;
|
||||
|
|
@ -228,10 +234,11 @@ namespace meta {
|
|||
enum {SIZ = lib::meta::count<typename Types<TYPES...>::List>::value };
|
||||
using Builder = BuildIndexSeq<SIZ>;
|
||||
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Descending = typename Builder::Descending;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename Builder::template FilledWith<x>;
|
||||
|
|
@ -245,6 +252,9 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ==== Manipulation of variadic arguments ==== **/
|
||||
|
||||
namespace { // Implementation delegate template...
|
||||
|
|
@ -274,6 +284,27 @@ namespace meta {
|
|||
return std::forward<ARG>(a);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal helper to decide if SelectVararg shall be applied.
|
||||
* When the boolean condition does not hold, then, instead of selecting
|
||||
* from the argument list, an element of type DEFAULT is created as fallback.
|
||||
*/
|
||||
template<bool, typename, size_t idx>
|
||||
struct SelectOrInit
|
||||
: SelectVararg<idx>
|
||||
{ };
|
||||
|
||||
template<typename DEFAULT, size_t idx>
|
||||
struct SelectOrInit<false, DEFAULT, idx>
|
||||
{
|
||||
template<typename...ARGS>
|
||||
static DEFAULT
|
||||
get (ARGS&&...)
|
||||
{
|
||||
return DEFAULT{};
|
||||
}
|
||||
};
|
||||
}//(End)Implementation
|
||||
|
||||
|
||||
|
|
@ -305,20 +336,7 @@ namespace meta {
|
|||
constexpr inline auto
|
||||
pickInit (ARGS&&... args)
|
||||
{
|
||||
enum{
|
||||
SIZ = sizeof...(args),
|
||||
IDX = idx < SIZ? idx : 0
|
||||
};
|
||||
|
||||
return (idx < SIZ)? SelectVararg<IDX>::get (std::forward<ARGS> (args)...)
|
||||
: DEFAULT{};
|
||||
}
|
||||
|
||||
template<size_t, typename DEFAULT>
|
||||
constexpr inline DEFAULT
|
||||
pickInit ()
|
||||
{
|
||||
return DEFAULT{};
|
||||
return SelectOrInit<(idx < sizeof...(args)), DEFAULT, idx>::get (std::forward<ARGS> (args)...);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -185,23 +185,60 @@ namespace test {
|
|||
|
||||
// does not compile...
|
||||
// pickArg<3> (n1,n2,n3);
|
||||
|
||||
N<0> n0;
|
||||
CHECK (n0 != pickArg<0> (N<0>{}));
|
||||
CHECK (n0 == pickArg<0> (N<0>{n0}));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
check_pickInit ()
|
||||
{
|
||||
UNIMPLEMENTED ("pick or init");
|
||||
N<1> n1;
|
||||
N<2> n2;
|
||||
using N0 = N<0>;
|
||||
|
||||
CHECK (1 == (pickInit<0,int> (1,2) ));
|
||||
CHECK (2 == (pickInit<1,int> (1,2) ));
|
||||
CHECK (0 == (pickInit<2,int> (1,2) ));
|
||||
|
||||
CHECK (n1 == (pickInit<0,N0> (n1,n2) ));
|
||||
CHECK (n2 == (pickInit<1,N0> (n1,n2) ));
|
||||
N0 n0 = pickInit<3,N0> (n1,n2);
|
||||
CHECK (n0 != (pickInit<3,N0> (n1,n2) )); // same type (N<0>) but different new instance
|
||||
|
||||
CHECK ("N<0>" == typeStr(pickInit<2,N0> (n1,n2)));
|
||||
CHECK ("N<0>" == typeStr(pickInit<2,N0> (1,"2")));
|
||||
CHECK ("N<0>" == typeStr(pickInit<2,N0> ()));
|
||||
}
|
||||
|
||||
|
||||
template<class...ARGS, size_t...idx>
|
||||
static auto
|
||||
call_with_reversed_arguments (IndexSeq<idx...>, ARGS&& ...args)
|
||||
{
|
||||
return fun (pickArg<idx> (forward<ARGS>(args)...) ...);
|
||||
}
|
||||
|
||||
void
|
||||
check_reorderedArguments ()
|
||||
{
|
||||
UNIMPLEMENTED ("reorder arguments of function call");
|
||||
N<0> n0;
|
||||
N<1> n1;
|
||||
N<2> n2;
|
||||
N<3> n3;
|
||||
|
||||
cout << fun (n0,n1,n2,n3) << endl;
|
||||
|
||||
using Backwards = typename BuildIndexSeq<4>::Descending;
|
||||
using Back2 = typename BuildIndexSeq<2>::Descending;
|
||||
using After2 = typename BuildIndexSeq<4>::After<2>;
|
||||
|
||||
cout << call_with_reversed_arguments (Backwards(), n0,n1,n2,n3);
|
||||
cout << call_with_reversed_arguments (Back2() , n0,n1,n2,n3);
|
||||
cout << call_with_reversed_arguments (After2() , n0,n1,n2,n3);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue