From 4348cd462c1caebd9b97d3d31e74c4f06f5d5bf5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 29 Sep 2017 02:35:15 +0200 Subject: [PATCH] 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... --- src/lib/meta/variadic-helper.hpp | 62 ++++++++++++------- .../meta/variadic-argument-picker-test.cpp | 45 ++++++++++++-- 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/lib/meta/variadic-helper.hpp b/src/lib/meta/variadic-helper.hpp index e9c45df10..23bdda67b 100644 --- a/src/lib/meta/variadic-helper.hpp +++ b/src/lib/meta/variadic-helper.hpp @@ -150,6 +150,9 @@ namespace meta { { template using AppendElm = IndexSeq; + + template + using PrependElm = IndexSeq; }; /** @@ -159,10 +162,11 @@ namespace meta { template struct BuildIndexSeq { - using Ascending = typename BuildIndexSeq::Ascending::template AppendElm; + using Ascending = typename BuildIndexSeq::Ascending::template AppendElm; + using Descending = typename BuildIndexSeq::Descending::template PrependElm; template - using OffsetBy = typename BuildIndexSeq::template OffsetBy::template AppendElm; + using OffsetBy = typename BuildIndexSeq::template OffsetBy::template AppendElm; template using FilledWith = typename BuildIndexSeq::template FilledWith::template AppendElm; @@ -179,10 +183,11 @@ namespace meta { { using Empty = IndexSeq<>; - using Ascending = Empty; + using Ascending = Empty; + using Descending = Empty; template - using OffsetBy = Empty; + using OffsetBy = Empty; template using FilledWith = Empty; @@ -205,10 +210,11 @@ namespace meta { enum {SIZ = sizeof...(TYPES) }; using Builder = BuildIndexSeq; - using Ascending = typename Builder::Ascending; + using Ascending = typename Builder::Ascending; + using Descending = typename Builder::Descending; template - using OffsetBy = typename Builder::template OffsetBy; + using OffsetBy = typename Builder::template OffsetBy; template using FilledWith = typename Builder::template FilledWith; @@ -228,10 +234,11 @@ namespace meta { enum {SIZ = lib::meta::count::List>::value }; using Builder = BuildIndexSeq; - using Ascending = typename Builder::Ascending; + using Ascending = typename Builder::Ascending; + using Descending = typename Builder::Descending; template - using OffsetBy = typename Builder::template OffsetBy; + using OffsetBy = typename Builder::template OffsetBy; template using FilledWith = typename Builder::template FilledWith; @@ -245,6 +252,9 @@ namespace meta { + + + /* ==== Manipulation of variadic arguments ==== **/ namespace { // Implementation delegate template... @@ -274,6 +284,27 @@ namespace meta { return std::forward(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 + struct SelectOrInit + : SelectVararg + { }; + + template + struct SelectOrInit + { + template + 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::get (std::forward (args)...) - : DEFAULT{}; - } - - template - constexpr inline DEFAULT - pickInit () - { - return DEFAULT{}; + return SelectOrInit<(idx < sizeof...(args)), DEFAULT, idx>::get (std::forward (args)...); } diff --git a/tests/library/meta/variadic-argument-picker-test.cpp b/tests/library/meta/variadic-argument-picker-test.cpp index f0039965f..c8aa7e67a 100644 --- a/tests/library/meta/variadic-argument-picker-test.cpp +++ b/tests/library/meta/variadic-argument-picker-test.cpp @@ -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 + static auto + call_with_reversed_arguments (IndexSeq, ARGS&& ...args) + { + return fun (pickArg (forward(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); } - - };