deserialization issue after changing namespace to customise tag names for boost xml

旧时模样 提交于 2019-12-24 10:56:06

问题


I have made the below changes to have customised names for tags. And the below code changes worked successfully and i could create a xml doc with customised names.

namespace boost { namespace serialization {
    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const , Myclass::Pgroups>& p, unsigned) {
            ar & make_nvp("assetid", p.first) & make_nvp("assetdata", p.second);
        }
} }

namespace boost { namespace serialization {
    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const , values>& p, unsigned) {
            ar & make_nvp("hacc_groupid", p.first) & make_nvp("hacc_groupdata", p.second);
        }
} }

But this seems to be a problem deserialising the xml to the object, i get boost error

 template<class Archive, class Object>
   std::string serialise_to_string(const char* tag,Object & obj)
   {
     std::ostringstream os (std::ios::binary);
     Archive arch ( os );
     arch << boost::serialization::make_nvp(tag,obj);
     return os.str();
   }
   template<class Archive , class Object>
   void deserialise_to_obj( std::string const  &s1,Object &outObj)
   {
      std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
      Archive arch (is);
      arch >> boost::serialization::make_nvp("tag",outObj);
   };

Without boost namespace customisation the serialisation and deserialisation are perfectly working , but with change in boost namespace for having customised tag names , the deserialisation has issue .

Error with the above code , i.e with const in namespace argvoid serialize(Ar& ar,std::pair<int const , values>& p, unsigned)

In file included from main.cpp:1:
In file included from /usr/local/include/boost/archive/binary_oarchive.hpp:21:
In file included from /usr/local/include/boost/archive/binary_oarchive_impl.hpp:22:
In file included from /usr/local/include/boost/archive/basic_binary_oarchive.hpp:33:
In file included from /usr/local/include/boost/archive/detail/common_oarchive.hpp:22:
In file included from /usr/local/include/boost/archive/detail/interface_oarchive.hpp:23:
In file included from /usr/local/include/boost/archive/detail/oserializer.hpp:68:
/usr/local/include/boost/archive/detail/check.hpp:162:5: error: static_assert failed "typex::value"
    BOOST_STATIC_ASSERT(typex::value);
    ^                   ~~~~~~~~~~~~
/usr/local/include/boost/static_assert.hpp:70:41: note: expanded from macro 'BOOST_STATIC_ASSERT'
#     define BOOST_STATIC_ASSERT( ... ) static_assert(__VA_ARGS__, #__VA_ARGS__)
                                        ^             ~~~~~~~~~~~
/usr/local/include/boost/archive/detail/iserializer.hpp:603:13: note: in instantiation of function template specialization 'boost::archive::detail::check_const_loading<const int>' requested here
    detail::check_const_loading< T >();
            ^
/usr/local/include/boost/archive/detail/common_iarchive.hpp:66:18: note: in instantiation of function template specialization 'boost::archive::load<boost::archive::xml_iarchive, const int>' requested here
        archive::load(* this->This(), t);
                 ^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:78:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<const int>' requested here
        this->detail_common_iarchive::load_override(t.value());
                                      ^
/usr/local/include/boost/archive/xml_iarchive.hpp:95:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<const int>' requested here
        basic_xml_iarchive<Archive>::load_override(t);
                                     ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:68:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<const int> >' requested here
        this->This()->load_override(t);
                      ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:75:32: note: (skipping 45 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
        return *(this->This()) >> t;
                               ^
/usr/local/include/boost/archive/basic_xml_iarchive.hpp:78:39: note: in instantiation of function template specialization 'boost::archive::detail::common_iarchive<boost::archive::xml_iarchive>::load_override<Myclass>' requested here
        this->detail_common_iarchive::load_override(t.value());
                                      ^
/usr/local/include/boost/archive/xml_iarchive.hpp:95:38: note: in instantiation of function template specialization 'boost::archive::basic_xml_iarchive<boost::archive::xml_iarchive>::load_override<Myclass>' requested here
        basic_xml_iarchive<Archive>::load_override(t);
                                     ^
/usr/local/include/boost/archive/detail/interface_iarchive.hpp:68:23: note: in instantiation of function template specialization 'boost::archive::xml_iarchive_impl<boost::archive::xml_iarchive>::load_override<const boost::serialization::nvp<Myclass> >' requested here
        this->This()->load_override(t);

If const-ness is removed from the boost namespace , deserialise_to_obj and serialise_to_string functions ,the code compiles and runs without any issue but doesn't customise the tag name

Hope my information is clear, Iam stuck at an issue where iam really not sure whether the deserialisation to object can smoothly happen with customised tag names. Please advice me what has to be done

Sample code foe serialisation and deserialisation with custom tag names live at coliru

sample working code without deserialzation and custom tag names live at coliru

Thanks Tejas


回答1:


The cinch is in the const-ness of std::pair<>::first for std::map::value_type.

This is one of the very few cases where using const_cast makes sense:

namespace boost { namespace serialization {
    template<class Ar>
        inline void serialize(Ar & ar, std::pair<int const, values> & p, unsigned) {
            ar & make_nvp("assetid", const_cast<int&>(p.first)) & make_nvp("assetdata", p.second);
        }

    template <typename Ar>
        void serialize(Ar& ar,std::pair<int const, Myclass::Pgroups>& p, unsigned) {
            ar & make_nvp("hacc_groupid", const_cast<int&>(p.first)) & make_nvp("hacc_groupdata", p.second);
        }
} }

Incidentally, this is also what Boost Serialization does: http://www.boost.org/doc/libs/1_63_0/boost/serialization/utility.hpp

Full Working Demo

Updated: Also overrides the the item node name now

Live On Coliru

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <fstream>

#include <map>
#include <boost/serialization/map.hpp>
#include <boost/serialization/split_member.hpp>

using boost::serialization::make_nvp;

namespace MyDomain { // demonstrate ADL for serialize
    struct values
    {
        std::string name;
        std::string sex;
        values() : name("dummy"), sex("dummy") {};

        template<class Archive>   
            void serialize(Archive & ar, const unsigned int /*version*/) {
                ar & make_nvp("name", name);
                ar & make_nvp("sex", sex);
            }
    };

    struct Myclass {
        Myclass() { }

        template<class Archive>
            void serialize(Archive & ar, const unsigned int /*version*/)  {
                ar & make_nvp("etoto", e_group);
                ar & make_nvp("ptoto", p_group);
            }

        typedef std::map<int,values> groups;
        typedef std::map<int,groups> Pgroups;    

        groups  e_group;
        Pgroups p_group;
    };

    #define CUSTOM_MAP_SERIALIZE(Map, keyname, valuename) \
    template<class Ar> inline void serialize(Ar & ar, Map::value_type& p, unsigned) { \
            ar & make_nvp(keyname, const_cast<int&>(p.first)) & make_nvp(valuename, p.second); \
        }

    CUSTOM_MAP_SERIALIZE(Myclass::groups, "assetid", "assetdata")
    CUSTOM_MAP_SERIALIZE(Myclass::Pgroups, "hacc_groupid", "hacc_groupdata")
}

namespace boost { namespace serialization {

    #define OVERRIDE_NVP(T, name) \
       template <> inline const nvp<T> make_nvp(const char *, T &t) { return nvp<T>(name, t); } \
       template <> inline const nvp<T const> make_nvp(const char *, T const &t) { return nvp<T const>(name, t); }

    OVERRIDE_NVP(MyDomain::Myclass::groups::value_type,  "group_item")
    OVERRIDE_NVP(MyDomain::Myclass::Pgroups::value_type, "Pgroup_item")

    #undef OVERRIDE_NVP
} }

template<class Archive, class Object>
std::string serialise_to_string(Object const& assetlist)
{
    auto os = std::ostringstream(std::ios::binary);
    Archive arch { os, boost::archive::no_header };
    arch << make_nvp("Main", assetlist);
    return os.str();
}


template<class Archive , class Object>
void deserialise_to_obj(std::string const &s1,Object &outObj)
{
    std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
    Archive arch { is, boost::archive::no_header };
    arch >> make_nvp("Main", outObj);
}

MyDomain::Myclass create_data()
{
    MyDomain::Myclass object;
    MyDomain::values val1;
    object.e_group.insert( std::make_pair(1,val1) ) ;
    object.e_group.insert( std::make_pair(2,val1) ) ;
    object.p_group.insert( std::make_pair(1,object.e_group) ) ;
    object.p_group.insert( std::make_pair(2,object.e_group) ) ;   
    return object;
}

int main() {
    {
        MyDomain::Myclass obj = create_data() ;

        std::string s2 = serialise_to_string<boost::archive::xml_oarchive>(obj);

        //Save xml to a file
        {
            std::ofstream ofs("output1.xml");
            ofs << s2 << std::endl << std::endl;
            ofs.close();
        }

    }

    std::string content;
    {
        std::ifstream ifs("output1.xml");
        content.assign(std::istreambuf_iterator<char>(ifs), {});
        ifs.close();
    }
    {
        MyDomain::Myclass outObj;
        deserialise_to_obj<boost::archive::xml_iarchive>(content,outObj);
        //Print the object 
        for(auto &i:outObj.p_group){
            std::cout<<"\n"<<i.first<<"\n";
            for(auto &j:i.second){
                std::cout<<"\t"<<j.first<<"\t"<<j.second.name<<"\t"<<j.second.sex<<"\n";
            }
        }  
    }
}

Prints

1
    1   dummy   dummy
    2   dummy   dummy

2
    1   dummy   dummy
    2   dummy   dummy

With output1.xml

<Main class_id="0" tracking_level="0" version="0">
    <etoto class_id="1" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <group_item class_id="2" tracking_level="0" version="0">
            <assetid>1</assetid>
            <assetdata class_id="3" tracking_level="0" version="0">
                <name>dummy</name>
                <sex>dummy</sex>
            </assetdata>
        </group_item>
        <group_item>
            <assetid>2</assetid>
            <assetdata>
                <name>dummy</name>
                <sex>dummy</sex>
            </assetdata>
        </group_item>
    </etoto>
    <ptoto class_id="4" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <Pgroup_item class_id="5" tracking_level="0" version="0">
            <hacc_groupid>1</hacc_groupid>
            <hacc_groupdata>
                <count>2</count>
                <item_version>0</item_version>
                <group_item>
                    <assetid>1</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
                <group_item>
                    <assetid>2</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
            </hacc_groupdata>
        </Pgroup_item>
        <Pgroup_item>
            <hacc_groupid>2</hacc_groupid>
            <hacc_groupdata>
                <count>2</count>
                <item_version>0</item_version>
                <group_item>
                    <assetid>1</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
                <group_item>
                    <assetid>2</assetid>
                    <assetdata>
                        <name>dummy</name>
                        <sex>dummy</sex>
                    </assetdata>
                </group_item>
            </hacc_groupdata>
        </Pgroup_item>
    </ptoto>
</Main>


来源:https://stackoverflow.com/questions/43160092/deserialization-issue-after-changing-namespace-to-customise-tag-names-for-boost

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!