c++ - How to implement recursive "using"/extract template parameters -
so asked question deleted it, found interesting challenge.
they had weird type, , had run problem concat , range castable sequences not sequences (for obvious reasons)
template<unsigned... is> struct sequence{}; template<typename... is> struct concat{}; template<unsigned... is> struct concat<sequence<is...>> : public sequence<is...> {}; template<unsigned... is, unsigned... js, typename... rest> struct concat<sequence<is...>, sequence<js...>, rest...> : concat<sequence<is..., js...>, rest...> {};
so figured it'd interesting challenge right, making same type.
so first pass @ concat ran unexpected problems...how on earth 1 extract template parameters sequences? ended using function below:
template <unsigned... is,unsigned... js> constexpr auto concat_results(sequence<is...>,sequence<js...>) -> sequence<is...,js...> { return sequence<is...,js...>(); } template <typename seq1,typename seq2> using concat = decltype(concat_results(seq1(),seq2()));
bizarrely, think that's shortest way declare it, though little weird. however, concat_results useful (on references of sequences) , type can useful in other places. have better way that?
next range, did recursive struct helper:
template <unsigned n> struct nrange_helper { using range = concat<typename nrange_helper<n-1>::range,sequence<n>>; }; template <> struct nrange_helper<0> { using range = sequence<0>; }; template <unsigned n> using range = typename nrange_helper<n>::range;
again, weird, works...but feel there should better way. got one?
note: please check out std::integer_sequence
, specialization index_sequence
, make_index_sequence
, index_sequence_for
facilities.
if want declare them yourself, use inner types:
template <typename, typename> struct concat; template <unsigned... is, unsigned... js> struct concat<sequence<is...>,sequence<js...>> { using type = sequence<is..., js...>; }; template <unsigned n> struct range { using type = typename concat<typename range<n-1>::type, sequence<n>>::type; }; template <> struct range<0> { using type = sequence<0>; };
which can of course combined template aliases shorter final form:
template <typename, typename> struct concath; template <unsigned... is, unsigned... js> struct concath<sequence<is...>,sequence<js...>> { using type = sequence<is..., js...>; }; template <typename l, typename r> using concat = typename concath<l, r>::type;
and:
template <unsigned n> struct rangeh { using type = concat<typename rangeh<n-1>::type, sequence<n>>; }; template <> struct rangeh<0> { using type = sequence<0>; }; template <unsigned n> using range = typename rangeh<n>::type;
however, indeed, verbose. still, there little cruft here:
- baseline declaration
- specialization (to end recursion or limit "interesting" types)
- alias declaration
on other hand it's written once.
Comments
Post a Comment