Implementing meta-function zip in c++11

后端 未结 2 1693
名媛妹妹
名媛妹妹 2021-02-02 15:20

I am actually trying to see if I can get a minimal library that supports the very few operations I use from boost::fusion.

Here is what I have so far...



        
相关标签:
2条回答
  • 2021-02-02 15:29

    Seems to be doable with fully-fledged lists (that means head, tail and cons operations) and recursion. Tested with a snapshot of GCC 4.7, all the std stuff is from <type_traits>:

    struct nil {};
    
    template<typename T>
    struct is_nil: std::is_same<T, nil> {};
    
    template<typename... T>
    struct and_: std::true_type {};
    
    template<typename First, typename... Rest>
    struct and_<First, Rest...>
    : std::integral_constant<
        bool
        , First::value && and_<Rest...>::value
    > {};
    
    template<typename T>
    struct not_
    : std::integral_constant<bool, !T::value> {};
    
    template<typename... T>
    struct typelist;
    
    template<typename First, typename Second, typename... Rest>
    struct typelist<First, Second, Rest...> {
        typedef First head;
        typedef typelist<Second, Rest...> tail;
    };
    
    template<typename Last>
    struct typelist<Last> {
        typedef Last head;
        typedef nil tail;
    };
    
    template<typename T, typename List>
    struct cons;
    
    template<typename T, typename... Ts>
    struct cons<T, typelist<Ts...>> {
        typedef typelist<T, Ts...> type;
    };
    
    // workaround for:
    // sorry, unimplemented: cannot expand '...' into a fixed-length argument list
    template<template<typename...> class Template, typename... T>
    struct gcc_workaround {
        typedef Template<T...> type;
    };
    
    namespace detail {
    
    template<typename Sfinae, typename... Lists>
    struct zip;
    
    template<typename... Lists>
    struct zip<
        typename std::enable_if<and_<is_nil<typename Lists::tail>...>::value>::type
        , Lists...
    > {
        typedef typelist<typelist<typename Lists::head...>> type;
    };
    
    template<typename... Lists>
    struct zip<
        typename std::enable_if<and_<not_<is_nil<typename Lists::tail>>...>::value>::type
        , Lists...
    > {
        typedef typename cons<
            typelist<typename Lists::head...>
            , typename gcc_workaround<zip, void, typename Lists::tail...>::type::type
        >::type type;
    };
    
    } // detail
    
    template<typename... Lists>
    struct zip: detail::zip<void, Lists...> {};
    

    You might want to add error checking to all this (I'm thinking of invalid instantiations that are currently simply left as incomplete types). Frankly given the amount of time it took me to figure this out, I'd suggest sticking with Boost.MPL. Things like lazy evaluation (with which I wouldn't have needed to do the SFINAE stuff) are a boon and I'd don't like reinventing them. Plus the day it's C++11 enabled you reap the best of both worlds.


    I forgot to mention that Boost.MPL also has the advantages of genericity. It can work on any type that satisfies one of its sequence concept (it's also possible to non-intrusively adapt a preexisting type), whereas you force the use of typelist.

    0 讨论(0)
  • 2021-02-02 15:53

    This is the shortest implementation I've discovered:

    template <typename...> struct typelist { };   
    template <typename A,typename B> struct prepend;
    template <typename A,typename B> struct joincols;
    template <typename...> struct zip;    
    
    template <typename A,typename... B>
    struct prepend<A,typelist<B...> > {
      typedef typelist<A,B...> type;
    };
    
    template <>
    struct joincols<typelist<>,typelist<> > {
      typedef typelist<> type;
    };
    
    template <typename A,typename... B>
    struct joincols<typelist<A,B...>,typelist<> > {
      typedef typename
        prepend<
          typelist<A>,
          typename joincols<typelist<B...>,typelist<> >::type
        >::type type;
    };
    
    template <typename A,typename... B,typename C,typename... D>
    struct joincols<typelist<A,B...>,typelist<C,D...> > {
      typedef typename
        prepend<
          typename prepend<A,C>::type,
          typename joincols<typelist<B...>,typelist<D...> >::type
        >::type type;
    };
    
    template <>
    struct zip<> {
      typedef typelist<> type;
    };
    
    template <typename A,typename... B>
    struct zip<A,B...> {
      typedef typename joincols<A,typename zip<B...>::type>::type type;
    };
    
    0 讨论(0)
提交回复
热议问题