Search code examples
c++template-meta-programmingboost-fusion

Getting a list of member types from a boost fusion adapted struct


I have boost fusion adapted structs like this one:

struct A {
    int x;
    double y;
    std::string z;
};
BOOST_FUSION_ADAPT_STRUCT(
    A,
    x,
    y,
    z
)

I'd like to iterate over the types of the adaptation at compile time. E.g. if I have a class that wraps a type:

template <typename T> class Foo { ... };

then I'd like to be able to get type std::tuple<Foo<int>, Foo<double>, Foo<std::string>> given my struct A. I use std::tuple here just as an example; it can be another variadic type template class.

A c++17 solution would be welcome.


Solution

  • Helper for transforming adapted fusion struct to something like std::tuple:

    template<class Adapted, template<class ...> class Tuple = std::tuple>
    struct AdaptedToTupleImpl
    {
        using Size = boost::fusion::result_of::size<Adapted>;
    
        template<size_t ...Indices>
        static Tuple<typename boost::fusion::result_of::value_at_c<Adapted, Indices>::type...> 
            Helper(std::index_sequence<Indices...>);
    
        using type = decltype(Helper(std::make_index_sequence<Size::value>()));
    };
    
    template<class Adapted, template<class ...> class Tuple = std::tuple>
    using AdaptedToTuple = typename AdaptedToTupleImpl<Adapted, Tuple>::type;
    

    Validation:

    using AsTuple = AdaptedToTuple<A>;
    static_assert(std::is_same_v<std::tuple<int, double, std::string>, AsTuple>);
    

    Helper which applies metafunction to each type in tuple:

    template<class List, template<class> class Func> struct ForEachImpl;
    
    template<class ...Types, template<class ...> class List, template<class> class Func>
    struct ForEachImpl<List<Types...>, Func>
    {
        using type = List<Func<Types>...>;
    };
    
    template<class List, template<class> class Func>
    using ForEach = typename ForEachImpl<List, Func>::type;
    

    Validation:

    static_assert(std::is_same_v<ForEach<AsTuple, std::add_pointer_t>, std::tuple<int*, double*, std::string*>>);
    

    Also take a look at Boost.MP11 library. It has mp_transform metafunction which is equivalent to ForEach function described above.