我希望通过boost序列化界面添加能够序列化boost融合图的功能。我尝试过以下方法:
#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;
}
这给了我编译错误:
struct boost::fusion::map<boost::fusion::pair<fieldOne, int>,
boost::fusion::pair<fieldTwo, double> >’ has no member named ‘serialize’
显然,我需要自己实现这一点。在网上搜索了一些指导之后,我找到了这些答案
Boost fusion serialization of a class using BOOST_FUSION_ADAPT_ADT
How to serialize fusion::vector?
然而,所有这些答案(以及网络上的许多其他答案)都依赖于使用自定义函数调用序列化,例如:
fusion_serialize(ar, m);
但是,我想以我可以调用的方式序列化地图:
ar & m;
这样我就可以在其他模板函数中使用序列化了。反正有没有实现这个目标?
我已经尝试将此添加到我的源文件
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);
}
}
}
但是,这太普遍了,因为模板将匹配任何类型并且如果它不是融合映射则生成编译错误。我不知道如何修改上述内容,以便serialize
函数定义仅适用于boost::fusion::map
类型。有什么建议吗?
答案 0 :(得分:4)
您可以为任何Fusion地图一般实施序列化:
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));
}
} }
现在,这有效:
#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;
}
打印:
22 serialization::archive 10 0 0 42 3.1415926535897931
反序列化同时实施。
为了完整性:
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/fusion.hpp>
答案 1 :(得分:1)
(这是一个C ++ 11解决方案,也许它可以激发一个带有Boost.PP的C ++ 98,但它将会有更多的工作。)
是,
[that]过于笼统,因为模板将匹配任何类型并生成 如果它不是融合图,则编译错误。
...这使得serialize
函数与序列化库本身中包含的其他声明发生冲突(ambiguate)。
因此,在@sehe答案之上构建更多通用性,您可以使用以下内容。请注意,在这种情况下,您不需要#include
或假设序列,因此它适用于所有融合序列。关键是使用template <class...> class Sequence
。
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/support/is_sequence.hpp>
#include <boost/serialization/nvp.hpp>
#include <typeinfo> // typeid
#include <string>
#include <boost/fusion/support/pair.hpp>
namespace boost{
namespace fusion{
template<typename Archive>
struct item_serializer{
Archive& ar;
item_serializer(Archive& ar) : ar(ar){}
template<typename T>
void operator()(T& item) const{
ar & boost::serialization::make_nvp((std::string("item_") + typeid(T).name()).c_str(), item);
// ar & BOOST_SERIALIZATION_NVP(item); // for more conservative xml tag name
}
};
template<class Archive, class T1, class T2>
void serialize(Archive& ar, pair<T1, T2>& p, const unsigned int /*file_version*/){
T2& second = p.second;
ar & BOOST_SERIALIZATION_NVP(second);
}
template<
class Archive, template <class...> class Sequence, typename... Args
, typename = typename boost::enable_if_c<traits::is_sequence<Sequence<Args...>>::value>::type
>
void serialize(Archive& ar, Sequence<Args...>& s, const unsigned int /*file_version*/){
item_serializer<Archive> sr(ar);
for_each(s, sr);
}
}}
示例:
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/sequence/comparison/equal_to.hpp>
#include <sstream>
int main(){
boost::fusion::vector<int, char, double> vector_src(
3, '4', 5.41
), vector_dst;
boost::fusion::map<
boost::fusion::pair<struct fieldOne, int>,
boost::fusion::pair<struct fieldTwo, double>
> map_src{42, M_PI}, map_dst;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa << BOOST_SERIALIZATION_NVP(vector_src);
oa << BOOST_SERIALIZATION_NVP(map_src);
std::cout << oss.str();
std::istringstream iss(oss.str());
boost::archive::xml_iarchive ia(iss);
ia >> BOOST_SERIALIZATION_NVP(vector_dst);
ia >> BOOST_SERIALIZATION_NVP(map_dst);
assert(vector_src == vector_dst);
assert(map_src == map_dst);
}
输出:
<vector_src class_id="0" tracking_level="0" version="0">
<item_i>3</item_i>
<item_c>52</item_c>
<item_d>5.4100000000000001</item_d>
</vector_src>
<map_src class_id="1" tracking_level="0" version="0">
<item_N5boost6fusion4pairIZ4mainE8fieldOneiEE class_id="2" tracking_level="0" version="0">
<second>42</second>
</item_N5boost6fusion4pairIZ4mainE8fieldOneiEE>
<item_N5boost6fusion4pairIZ4mainE8fieldTwodEE class_id="3" tracking_level="0" version="0">
<second>3.1415926535897931</second>
</item_N5boost6fusion4pairIZ4mainE8fieldTwodEE>
</map_src>