Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
590 views
in Technique[技术] by (71.8m points)

c++ - How to de/serialize a map with template class using boost::multiprecision::mpq_rational

I have the following template class:

#include <map>
#include <boost/array.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/multiprecision/gmp.hpp>
template <class T>
class A {
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
        ar & a;
}
public:
  T a;
};

that I use to create a map.

map<A<boost::array<int,2> >, int> mmm;

I can use the header files provided by boost to serialize/deserialize this code using:

 ifstream ifs("filename");
 boost::archive::text_iarchive iarch(ifs);
 boost::serialization::load<boost::archive::text_iarchive,int,A<boost::array<int,2> > >(iarch,mmm,1);

Question: I would like to use boost::multiprecision::mpq_rational instead of int inside the array. However I get a long error with the main complaint being that gmp_backend does not have a serialize method:

....
/usr/local/include/boost/serialization/access.hpp:118:9: error: ‘struct boost::multiprecision::backends::gmp_rational’ has no member named ‘serialize’
     t.serialize(ar, file_version);
     ^

Is there an easy fix using boost/serialization/map.hpp with mpq_rational? Thanks,

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There's passthrough support for Boost Multiprecision serialization:

Classes number, debug_adaptor, logged_adaptor and rational_adaptor have "pass through" serialization support which requires the underlying backend to be serializable.

Backends cpp_int, cpp_bin_float, cpp_dec_float and float128 have full support for Boost.Serialization.

That is to say, it's supported iff the backend supports it: mailing list:

> Does/will multiprecesion have support for boost::serialization?

Good question, and no not yet. I guess it should do though... it's hard though as some backends (for example GMP's mpf_t) don't round trip to and from string representations, and have an internal structure that probably shouldn't be relied upon :-

You can:

  • use cpp_rational (as it is supported implicitly by the above doc excerpt)
  • use Boost Rational: How to serialize boost::rational
  • use raw mpz_* API to serialize, see e.g. How to serialize a GMP rational number?

  • you can explicitly add serialization support for the backend (note that using the gmp API's will be more efficient)

    namespace boost { namespace serialization {
    
        template <typename Archive>
            void save(Archive& ar, ::boost::multiprecision::backends::gmp_rational const& r, unsigned /*version*/)
            {
                std::string tmp = r.str(10000, std::ios::fixed);
                ar & tmp;
            }
    
        template <typename Archive>
            void load(Archive& ar, ::boost::multiprecision::backends::gmp_rational& r, unsigned /*version*/)
            {
                std::string tmp;
                ar & tmp;
                r = tmp.c_str();
            }
    
    } }
    
    BOOST_SERIALIZATION_SPLIT_FREE(::boost::multiprecision::backends::gmp_rational)
    

Here's a demo Live On Coliru with a simple roundtrip test.

Full Listing

#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/multiprecision/gmp.hpp>
#include <boost/multiprecision/rational_adaptor.hpp>
#include <iostream>

namespace boost { namespace serialization {

    template <typename Archive>
        void save(Archive& ar, ::boost::multiprecision::backends::gmp_rational const& r, unsigned /*version*/)
        {
            std::string tmp = r.str(10000, std::ios::fixed);
            ar & tmp;
        }

    template <typename Archive>
        void load(Archive& ar, ::boost::multiprecision::backends::gmp_rational& r, unsigned /*version*/)
        {
            std::string tmp;
            ar & tmp;
            r = tmp.c_str();
        }

} }

BOOST_SERIALIZATION_SPLIT_FREE(::boost::multiprecision::backends::gmp_rational)

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/array.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/serialization.hpp>
#include <map>

template <class T>
class A {
    friend class boost::serialization::access;
    template<class Archive>
        void serialize(Archive & ar, const unsigned int version)
        {
            ar & a;
        }

  public:
    T a;
    bool operator<(A const& o) const { return a<o.a; }
};

#include <sstream>

using KeyElement = boost::multiprecision::mpq_rational;
using Key        = A<boost::array<KeyElement,2> >;
using Data       = std::map<Key, int>;

int main()
{
    std::stringstream ss;
    {
        Data mmm { 
            { Key {{{KeyElement { 1, 2 }, KeyElement { 3, 4 }} }}, 5 }, 
            { Key {{{KeyElement { 6, 7 }, KeyElement { 8, 9 }} }}, 42 },
        };
        boost::archive::text_oarchive oa(ss);

        oa << mmm;
    }

    std::cout << "Serialized:" << ss.str() << "
";

    {
        boost::archive::text_iarchive iarch(ss);
        Data mmm; 
        iarch >> mmm;

        std::cout << "Roundtrip:";
        boost::archive::text_oarchive oa(std::cout);
        oa << mmm;
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.8k users

...