折叠任意多个可变包 [英] Folding over arbitrarily many variadic packs

查看:112
本文介绍了折叠任意多个可变包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过Eric Niebler的帖子阅读他的小元编程库。在尝试实现他忽略/列出的作品作为挑战,我留下以下实现 transform

I'm reading through Eric Niebler's post on his tiny metaprogramming library. In trying to implement the pieces that he omits / lists as challenges, I am left with the following implementation of transform:

template <typename F, typename... As>
using meta_apply = typename F::template apply<As...>;

template <typename... >
struct typelist_transform;

// unary
template <typename... T, typename F>
struct typelist_transform<typelist<T...>, F> 
{
    using type = typelist<meta_apply<F,T>...>;
};

// binary
template <typename... T, typename... U, typename F>
struct typelist_transform<typelist<T...>, typelist<U...>, F>
{
    using type = typelist<meta_apply<F,T,U>...>;
};

这样可以工作,但对我来说似乎非常不满意 - 我需要一个部分专门化 typelist_transform F 中的每个数字的参数。

This works, but seems very unsatisfactory to me - I need a partial specialization of typelist_transform for every number of "arguments" into F. Is there a better way to implement this metafunction?

推荐答案

使用稍微修改的接口(首先采用元函数,而不是最后一个,并添加一些成员到 typelist 以获得其大小和第N个成员,而不是使用独立的元函数):

With a slightly modified interface (taking the metafunction first, rather than last, and adding a couple members to typelist to get its size and the N-th member rather than using standalone metafunctions):

template <typename... Ts>
struct typelist {
    template<size_t N>
    using get = std::tuple_element_t<N, std::tuple<Ts...>>;
    static constexpr size_t size = sizeof...(Ts);
};

template<class, class, class...>
struct typelist_transform_helper;

template<size_t... Ints, class F, class...Lists>
struct typelist_transform_helper<std::index_sequence<Ints...>, F, Lists...>{
    template <class MF, size_t N, typename... Ls>
    using apply_to_Nth = meta_apply<MF, typename Ls::template get<N>...>;

    using type = typelist<apply_to_Nth<F, Ints, Lists...>...>;
};

template<class F, class L1, class... Lists>
struct typelist_transform : typelist_transform_helper<std::make_index_sequence<L1::size>, F, L1, Lists...> {
    // static assert on size of all lists being equal if wanted
};

演示

上述问题之一是 tuple_element 通常需要 N 递归模板实例化,使得模板实例化的总数在列表长度上是二次的。给定我们的用例(我们访问每个单独的索引),我们可以做得更好:

One problem with the above is that tuple_element usually requires N recursive template instantiations, making the total number of template instantiations quadratic in the length of the list. Given our use case (we access every single index), we can do better:

template<class L>
struct typelist_indexer {
    template<size_t N, class T> struct helper_base { using type = T; };

    template<class S, class> struct helper;
    template<size_t... Ns, class... Ts> 
    struct helper<std::index_sequence<Ns...>, typelist<Ts...>> : helper_base<Ns, Ts>... {};

    template<size_t N, class T>
    static helper_base<N, T> do_get(helper_base<N, T>);

    using helper_type = helper<std::make_index_sequence<L::size>, L>;

    template<size_t N>
    using get = typename decltype(do_get<N>(helper_type()))::type;
};

,然后

template<size_t... Ints, class F, class...Lists>
struct typelist_transform_helper<std::index_sequence<Ints...>, F, Lists...>{
    template <class MF, size_t N, typename... Ls>
    using apply_to_Nth = meta_apply<MF, typename typelist_indexer<Ls>::template get<N>...>;

    using type = typelist<apply_to_Nth<F, Ints, Lists...>...>;
};

现在模板实例化的数量在列表大小中是线性的,在显着的编译时间改进。 演示

Now the number of template instantiations is linear in the size of the list, and in my tests this result in a significant compile time improvement. Demo.

这篇关于折叠任意多个可变包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆