如何实现递归“使用”/提取模板参数(How to implement recursive “using”/extract template parameters)

编程入门 行业动态 更新时间:2024-10-28 20:22:28
如何实现递归“使用”/提取模板参数(How to implement recursive “using”/extract template parameters)

所以有人问了一个问题然后将其删除了,但我发现这是一个有趣的挑战。

他们有这种奇怪的类型,并且遇到了Concat和Range可以转换为Sequences但不是Sequences的问题(出于显而易见的原因)

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...> {};

所以我认为做正确的事情是一个有趣的挑战,让一切都变成相同的类型。

所以我在Concat的第一次传递遇到了意想不到的问题......究竟如何提取序列的模板参数? 我最终使用了以下功能:

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

奇怪的是,我认为这是宣告它的最短路,尽管有点奇怪。 但是,concat_results可能是有用的(在序列的引用上),并且该类型在其他地方可能是有用的。 有人有更好的方法吗?

接下来是范围,我用一个递归的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;

再次,它很奇怪,但它的作用......但我觉得应该有更好的方法。 谁有人?

So someone asked a question then deleted it, but I found it an interesting challenge.

They had this weird type, and had run into the problem that Concat and Range were castable to Sequences but were 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 I figured it'd be an interesting challenge to do this right, making everything the same type.

So my first pass at Concat ran into unexpected problems...How on earth does one extract the template parameters for the Sequences? I ended up using a 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, I think that's the shortest way to declare it, though it is a little weird. However, the concat_results could be useful (on references of the sequences) and the type can be useful in other places. Anyone have a better way to do that?

Next up was range, which I did with a 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, its weird, but it works...but I feel like there should be a better way. Anyone got one?

最满意答案

注意:请查看std::integer_sequence ,其特化index_sequence及其make_index_sequence和index_sequence_for工具。

如果你想自己声明它们,你通常会使用内部类型:

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

当然可以将其组合到模板别名中以获得更短的最终形式:

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;

和:

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;

但实际上,这有点冗长。 不过,这里几乎没有什么东西:

基线声明 专业化(结束递归或限制为“有趣”类型) 别名声明

另一方面,它只写了一次。

Note: please check out std::integer_sequence, its specialization index_sequence and its make_index_sequence and index_sequence_for facilities.

If you want to declare them yourself, you generally would 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 be combined to template aliases for a 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, this is slightly verbose. Still, there is little cruft here:

baseline declaration specialization (to end recursion or limit to "interesting" types) alias declaration

on the other hand it's only written once.

更多推荐

本文发布于:2023-08-01 21:00:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1365167.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:递归   如何实现   模板   参数   implement

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!