Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何为boost fusion地图添加boost归档序列化支持?_C++_Serialization_Boost - Fatal编程技术网

C++ 如何为boost fusion地图添加boost归档序列化支持?

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

我想添加能够通过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/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>