From b5af8dbb51b662d5ec6c346ed71ffba6f7de4c0e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 28 Sep 2017 02:49:53 +0200 Subject: [PATCH] Investigation: cleaner solution for default initialisation Handle corner cases within the front-end functions, either by static assert or direct branching; keeps the variadic implementation template clean --- research/try.cpp | 78 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 8faa5d849..666f54078 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -95,46 +95,79 @@ using lib::meta::BuildIndexSeq; using lib::meta::BuildIdxIter; -template +namespace { +/** + * @internal pick a single argument from a variadic parameter pack + * @tparam i the index number (zero based) of the argument to select + * @warning i must be smaller than the number of arguments available + */ +template struct SelectVararg { template static auto - get (ARG, ARGS ...args) + get (ARG, ARGS&& ...args) { - return SelectVararg::get (args...); + return SelectVararg::get (std::forward (args)...); } - - static INIT get() { return INIT{}; } }; -template -struct SelectVararg<0, INIT> +template<> +struct SelectVararg<0> { template - static ARG - get (ARG a, ARGS...) + static auto + get (ARG&& a, ARGS...) { - return a; + return std::forward(a); } - - static INIT get() { return INIT{}; } }; +} + +/** + * Helper to single out one argument from a variadic argument pack. + * @tparam idx the index number (zero based) of the argument to select + * @remark typically this function is used "driven" by an likewise variadic index sequence, + * where the index sequence itself is picked up by a pattern match; this usage pattern + * allows arbitrarily to handle some of the arguments of a variable argument list, + * as determined by the index sequence passed in. + */ template constexpr inline auto -pickArg (ARGS... args) +pickArg (ARGS&&... args) { - return SelectVararg::get (args...); + static_assert (idx < sizeof...(args), "insufficient number of arguments"); + + return SelectVararg::get (std::forward (args)...); } -template +/** + * Helper to pick one initialisation argument from a variadic argument pack, + * falling back to a default constructed element of type `DEFAULT` in case of + * insufficient number of variadic arguments. + * @tparam idx the index number (zero based) of the argument to select + * @tparam DEFALUT type of the default element to construct as fallback + */ +template constexpr inline auto -pickInit (ARGS... args) +pickInit (ARGS&&... args) { - return SelectVararg::get (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{}; + } using Arr = std::array; @@ -172,8 +205,17 @@ main (int, char**) auto arr = dispatch (2,3,4,5,6,7,8); cout << util::join(arr) << "| " << showSizeof(arr) <