alibaba / yalantinglibs

A collection of modern C++ libraries, include coro_rpc, struct_pack, struct_json, struct_xml, struct_pb, easylog, async_simple
https://alibaba.github.io/yalantinglibs/
Apache License 2.0
1.55k stars 240 forks source link

[struct_xml] struct_xml::to_xml一个包含std::map<int, int>的对象,执行struct_xml::to_xml时崩溃。且不能支持struct_pack::compatible做成员变量 #780

Open xiaocai123123 opened 2 months ago

xiaocai123123 commented 2 months ago

代码如下

#include <cassert>
#include <iostream>

#include "ylt/struct_xml/xml_reader.h"
#include "ylt/struct_xml/xml_writer.h"
#include <ylt/struct_pack.hpp>

struct person {
    std::string name;
    int age;
    std::list<int> list;
    std::vector<int> vec;
    std::map<int, int> idx2Int;
    //struct_pack::compatible<int, 114514> c1;
};

bool operator==(const person& a, const person& b) {
    return a.name == b.name && a.age == b.age;
}

YLT_REFL(person, name, list, age, vec, idx2Int/*, c1*/);

int main() {
    person p{ "tom", 20 , {1,2,3}, {1,2,3}, { {1, 11}, {2, 21}} /*, 11*/ };
    std::string str;

    // struct to xml
    struct_xml::to_xml<true>(p, str);
    std::cout << str << "\n";

    // struct from xml
    person p1;
    struct_xml::from_xml(p1, str);
    assert(p1.name == p.name);
    return 0;
}

问题1,因为person里有成员变量std::map<int, int> idx2Int,所以执行到struct_xml::to_xml(p, str);时崩溃。崩溃如下图 image 问题2,如果打开struct_pack::compatible<int, 114514> c1;相关的注释,编译不通过,编译报错如下图 image

因为我想让结构体person同时使用struct_pack、struct_xml、struct_json,且想保证不同版本的前后兼容性。且能支持std常用的容器,如std::map。谢谢!

qicosmos commented 2 months ago

xml是不支持map的,没有xml结构可以和map对应,map只是用来保存属性才能用而不是直接作为成员,可以看看struct_xml 的例子,如果字段中有map类型则会抛出一个bad function call的异常。

https://github.com/qicosmos/iguana/blob/master/test/test_xml.cpp#L774

qicosmos commented 2 months ago

这个对象to_json 是没问题的,因为json支持map结构。

xiaocai123123 commented 2 months ago

xml是不支持map的,没有xml结构可以和map对应,map只是用来保存属性才能用而不是直接作为成员,可以看看struct_xml 的例子,如果字段中有map类型则会抛出一个bad function call的异常。

https://github.com/qicosmos/iguana/blob/master/test/test_xml.cpp#L774

感谢答复! json是可以支持std::map的,我测试过。xml的话,我刚试过了boost的序列化,也是可以支持的。boost测试代码如下

#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <iostream> 
#include <fstream> 
#include <list> 
#include <vector> 
#include <map> 
struct person {
    std::string name;
    int age;
    std::list<int> list;
    std::vector<int> vec;
    std::map<int, int> idx2Int;
    //struct_pack::compatible<int, 114514> c1;
};
namespace boost {
    namespace serialization {

        template<class Archive>
        void serialize(Archive& archive, person& p, const unsigned int version)
        {
            archive& BOOST_SERIALIZATION_NVP(p.name);
            archive& BOOST_SERIALIZATION_NVP(p.age);
            archive& BOOST_SERIALIZATION_NVP(p.list);
            archive& BOOST_SERIALIZATION_NVP(p.vec);
            archive& BOOST_SERIALIZATION_NVP(p.idx2Int);
        }

    } // namespace serialization
}

int main(int argc, char* argv[])
{
    // struct to xml
    {
        std::ofstream file("archive.xml");
        boost::archive::xml_oarchive oa(file);
        person p{ "tom", 20 , {1,2,3}, {1,2,3}, { {1, 11}, {2, 21}} /*, 11*/ };
        oa& BOOST_SERIALIZATION_NVP(p);
    }
    // struct from xml
    {
        person p1;
        try
        {
            std::ifstream file("archive.xml");
            boost::archive::xml_iarchive ia(file);
            ia >> BOOST_SERIALIZATION_NVP(p1);
        }
        catch (const std::exception& e)
        {
            std::string vv = e.what();
        }
    }
    return 0;
}

boost测试代码产生的xml文件内容如下

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="19">
<p class_id="0" tracking_level="0" version="0">
    <p.name>tom</p.name>
    <p.age>20</p.age>
    <p.list>
        <count>3</count>
        <item_version>0</item_version>
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </p.list>
    <p.vec>
        <count>3</count>
        <item_version>0</item_version>
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </p.vec>
    <p.idx2Int class_id="3" tracking_level="0" version="0">
        <count>2</count>
        <item_version>0</item_version>
        <item class_id="4" tracking_level="0" version="0">
            <first>1</first>
            <second>11</second>
        </item>
        <item>
            <first>2</first>
            <second>21</second>
        </item>
    </p.idx2Int>
</p>
</boost_serialization>

如果xml能支持std::map就好了,这样与使用更方便,不用考虑json转xml时还要修改结构体数据类型。