c++boostfusion

Initialize boost::fusion::map values


I have a boost::fusion::map like this:

struct bar {};
struct baz {};

template<typename... Args>
struct foo
{
    foo(bar &, baz &) {}
};

template<typename... T>
using MapEntry = boost::fusion::pair<boost::mpl::set<T...>, foo<T...>>;

using Map = boost::fusion::map<
            MapEntry<int, bool, double>,
            MapEntry<std::string>,
            MapEntry<int64_t, uint32_t>,
            MapEntry<char, uint64_t>
            // ...
            >;

then need to initialize instanse of Map, passing bar_ and baz_ into all foo constructors.

At the moment, I have :

int main()
{
    bar bar_;
    baz baz_;

    Map map_(
        boost::fusion::make_pair<boost::mpl::set<int, bool, double>>(foo<int, bool, double>(bar_, baz_)),
        boost::fusion::make_pair<boost::mpl::set<std::string>>(foo<std::string>(bar_, baz_)),
        boost::fusion::make_pair<boost::mpl::set<int64_t, uint32_t>>(foo<int64_t, uint32_t>(bar_, baz_)),
        boost::fusion::make_pair<boost::mpl::set<char, uint64_t>>(foo<char, uint64_t>(bar_, baz_))
        // ...
    );

    return 0;
}

But this is very redundant. Is it possible to make this code cleaner ?


Solution

  • At first create a function to create MapEntry

    template<typename E, typename... Args>
    E make_map_entry(Args &&...args)
    {
        return boost::fusion::make_pair<E::first_type>(E::second_type(std::forward<Args>(args)...));
    }
    

    At second create a function to create Map, it uses helper function that unroll make_map_entry for each entry

    template<typename M, std::size_t ...I, typename... Args>
    M make_map_impl(std::index_sequence<I...>, Args &&...args)
    {
        return M(make_map_entry<boost::fusion::result_of::value_at_c<M, I>::type>(std::forward<Args>(args)...)...);
    }
    
    template<typename M, typename... Args>
    M make_map(Args &&...args)
    {
        return make_map_impl<M>(std::make_index_sequence<boost::fusion::result_of::size<M>::value> {}, args...);
    }
    

    then we can write

    int main()
    {
        bar bar_;
        baz baz_;
    
        Map map(make_map<Map>(bar_, baz_));
    
        return 0;
    }