C++ 如何为boost fusion地图添加boost归档序列化支持?
我想添加能够通过boost序列化接口序列化boost fusion映射的功能。我尝试了以下方法:C++ 如何为boost fusion地图添加boost归档序列化支持?,c++,serialization,boost,C++,Serialization,Boost,我想添加能够通过boost序列化接口序列化boost fusion映射的功能。我尝试了以下方法: #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 <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;
}
但是,我希望以一种可以调用的方式序列化映射:
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);
}
}
}
namespace boost{
命名空间序列化{
模板
无效序列化(存档和ar、T和map、常量未签名整数版本){
fusion_序列化(ar、map);
}
}
}
但是,这太笼统了,因为如果模板不是融合映射,它将匹配任何类型并生成编译错误。我不知道如何修改上述内容,使
serialize
函数定义仅适用于boost::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));
}
} }
同时实现反序列化
完整性:
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/fusion.hpp>
#包括
#包括
#包括
#包括
(这是一个C++11解决方案,也许它可以激发C++98与Boost.PP的结合,但这将是更多的工作。)
对
[这]太笼统了,因为模板将匹配任何类型并生成
如果不是融合贴图,则编译错误
…这使得序列化函数与序列化库本身中包含的其他声明发生冲突(歧义)
因此,在@sehe-answer的基础上构建更多的泛型,您可以使用以下方法。请注意,在本例中,您不需要包含或假设序列,因此它适用于所有融合序列。关键是使用模板类序列
#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//typeid
#包括
#包括
名称空间提升{
名称空间融合{
模板
结构项\序列化程序{
档案与应收账款;
项_序列化程序(存档和ar):ar(ar){}
模板
void运算符()(T和item)常量{
ar&boost::serialization::make_nvp((std::string(“item”)+typeid(T.name()).c_str(),item);
//ar&BOOST_SERIALIZATION_NVP(item);//有关更保守的xml标记名
}
};
模板
无效序列化(存档和ar、配对和p、常量未签名int/*文件\u版本*/){
T2&second=p.second;
ar和BOOST_序列化_NVP(第二);
}
模板<
类存档、模板类序列、typename…参数
,typename=typename boost::启用\u if_c::type
>
无效序列化(存档和ar、序列和s、常量无符号int/*文件\u版本*/){
项目\序列化程序sr(ar);
各(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);
}
#包括
#包括
#包括
#包括
#包括
#包括
int main(){
boost::fusion::vector\u src(
3, '4', 5.41
),向量单位;
boost::fusion::map<
boost::fusion::pair,
boost::fusion::pair
>map_src{42,M_PI},mapdst;
std::ostringstream oss;
boost::archive::xml_oarchive oa(oss);
oa>BOOST_序列化_NVP(map_dst);
断言(vector_src==vector_dst);
断言(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>
3.
52
5.4100000000000001
42
3.1415926535897931
template void serialize(Archive&ar、tFusionMap&m、const unsigned int version)应该有效这只适用于我的tFusionMap
,但是,我希望序列化适用于所有fusioan mapsWow,谢谢!没有C++11有没有办法做到这一点?是的,但会更加冗长。对于N种类型的映射,您必须使用多个特殊化(这里的变量可以节省时间)。对于其他人,没有重大挑战。因此,如果没有C++11,我需要为每一个可能的参数数量添加一个模板专门化?这就是训练,是的。如果你想偷懒,你可以用预处理器宏做“假变量”。请参见BOOST.pp谢谢!这是一个非常优雅的解决方案。理想情况下,我想在没有C++11的情况下实现这一点,但我想这只能通过难看的预处理器宏向导来实现:-)。也许可以通过BOOST.PP
实现,但我不打算尝试。
#include <boost/fusion/include/map.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/fusion.hpp>
#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>