问题
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