How do I add boost archive serialization support for boost fusion maps?

boost, c++, serialization

Solution

You can generically implement serialization for any Fusion map:

namespace boost { namespace serialization {

    struct saver {
        template <typename Ar, typename Pair>
            void operator()(Ar& ar, Pair& data) const
            {
                ar & data.second;
            }
    };

    template <typename Ar, typename... TArgs>
        void serialize(Ar& ar, boost::fusion::map<TArgs...>& fmap, unsigned /*version*/)
        {
            using phoenix::ref;
            using phoenix::arg_names::arg1;
            static const phoenix::function<saver> save {};

            fusion::for_each(fmap, save(ref(ar), arg1));
        }

} }

Now, this works:

#include <boost/archive/text_oarchive.hpp>
#include <iostream>

typedef boost::fusion::map<
    boost::fusion::pair<struct fieldOne, int>,
    boost::fusion::pair<struct fieldTwo, double> 
  > tFusionMap;

int main() {
    tFusionMap map { 42 , M_PI };
    boost::archive::text_oarchive oa(std::cout);
    oa & map;
}

See it Live On Coliru

Prints:

22 serialization::archive 10 0 0 42 3.1415926535897931

Deserialization is implemented at the same time.

For completeness:

#include <boost/fusion/include/map.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/fusion.hpp>

Problem

I'd like to add the functionality to be able to serialize boost fusion maps via the boost serialization interface. I've tried the following: ``` #include <iostream> #include <boost/fusion/container/map.hpp> #include <boost/fusion/include/map.hpp> #include <boost/fusion/container/map/map_fwd.hpp> #include <boost/fusion/include/map_fwd.hpp> #include <boost/fusion/sequence/intrinsic/at_key.hpp> #include <boost/fusion/include/at_key.hpp> #include <boost/fusion/include/io.hpp> #include <boost/archive/text_iarchive.hpp> struct fieldOne {}; struct fieldTwo {}; typedef boost::fusion::map< boost::fusion::pair<fieldOne, int>, boost::fusion::pair<fieldTwo, double> > tFusionMap; int main() { tFusionMap map; boost::archive::text_iarchive ar(std::cin); std::cin >> map; /* no compile error */ ar & map; /* compiler error: */ return 0; } ``` which gives me the compiler error: ``` struct boost::fusion::map<boost::fusion::pair<fieldOne, int>, boost::fusion::pair<fieldTwo, double> >’ has no member named ‘serialize’ ``` so apparently I need to implement this myself. After searching the web for some guidance, I found these answers Boost fusion serialization of a class using BOOST_FUSION_ADAPT_ADT How to serialize fusion::vector? however, all of theses answers (and many others on the web) rely on invoking the serialization with a custom function, for example: ``` fusion_serialize(ar, m); ``` However, I would like to serialize the map in a way that I can call: ``` ar & m; ``` so that I can use the serialization in other template functions. Is there anyway to achieve this? I've tried adding this to my source file ``` namespace boost { namespace serialization { template<class Archive, typename T, std::size_t num_dims> void serialize( Archive & ar, T & map, const unsigned int version ) { fusion_serialize(ar,map); } } } ``` However, this is too general as the template will match ANY type and generate compile errors if it is not a fusion map. I don't see how I can modify the above so that the `serialize` function definition only applies to `boost::fusion::map` types. Any suggestions?

Original source