2015-05-27 25 views
4

我正在通過Eric Niebler的post在他的小型元編程庫中閱讀。在試圖實現他省略了片/列爲挑戰,我留下了以下實施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。有沒有更好的方法來實現這個元函數?

回答

4

隨着稍微修改的接口(以元函數第一,而不是最後,添加了幾個成員typelist得到它的大小和第N構件,而不是使用單獨的元函數):

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

Demo。與上述


的一個問題是tuple_element通常需要N遞歸模板實例,使得在列表的長度二次模板實例的總數。由於我們使用的情況下(我們訪問的每一個指標),我們可以做的更好:

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

現在模板實例的數量是在列表的大小呈線性關係,並在我的測試結果顯着提高了編譯時間。 Demo

+0

我想你可以用'tuple_element'類似的技巧來繼續保留元函數。 – Barry

+0

@Barry是的,它可以做到。它只是少一些代碼。 –