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); } - - };