C++ 转换C++;类转换为JSON

C++ 转换C++;类转换为JSON,c++,json,serialization,C++,Json,Serialization,我想创建一个包含类的实例变量的JSON字符串 比如说, class Example { std::string string; std::map<std::string, std:string> map; std::vector<int> vector; }; 我已经研究了几个用于创建JSON的C++库,它们看起来都非常复杂。我想要类似Javascript的JSON.stringify(object)。换句话说,只需将std::m

我想创建一个包含类的实例变量的JSON字符串

比如说,

class Example {  
    std::string string;  
    std::map<std::string, std:string> map;  
    std::vector<int> vector;  
};
我已经研究了几个用于创建JSON的C++库,它们看起来都非常复杂。我想要类似Javascript的
JSON.stringify(object)
。换句话说,只需将std::map传递给它并接收字符串。地图可以包含其他地图、向量、列表、字符串、数字和布尔值

最好的方法是什么

谢谢你的帮助

编辑

我已经研究了以下内容:

json spirit、jsoncpp、zoolib、JOST、CAJUN、libjson、nosjob、JsonBox、jsonme--

我知道我可以构建一个单独的JSON对象,如下面的答案所示,并转换为JSON。我希望能够将我的东西存储在标准集合中,并进行转换

编辑2

好吧,放弃序列化类的想法,因为C++缺乏反射,这似乎是不可能的

有没有一种好方法可以将包含std:maps、std::vectors、std::list、number、string和bools的std::map转换为JSON,而无需更改数据类型或将数据复制到新的数据类型

谢谢。

将允许您这样做:

Object addr_obj;

addr_obj.push_back( Pair( "house_number", 42 ) );
addr_obj.push_back( Pair( "road",         "East Street" ) );
addr_obj.push_back( Pair( "town",         "Newtown" ) );

ofstream os( "address.txt" );
os.write( addr_obj, os, pretty_print );
os.close();
输出:

{
    "house_number" : 42,
    "road" : "East Street",
    "town" : "Newtown"
}

我想这将是一个很好的起点。

你想要一个地图还是一个对象?(您的示例显示了一个类,但您说的是一个映射)。有关地图,请查看此库-


对象:在C++中没有反射支持(除了非常有限的RTTI),所以也没有“一键”的串行化解决方案。任何解决方案都需要您为要序列化和反序列化的类编写额外的、可能是紧密耦合的代码(这取决于您是否要序列化非公共数据)。

我编写了一个库,旨在解决您的问题。 然而,这是一个非常新的项目,不够稳定。 请随意查看,主页如下:

在您的示例中,必须添加一行,如下所示:

ACML_REGISTER(Example, ,(string)(map)(vector));
以便告诉库您要转储哪个成员。 因为C++没有反射。 您必须提供一种访问成员的方式, 使用公共成员级别或使用好友类

以后你只需要做这样的事情:

ACML_REGISTER(Example, ,(string)(map)(vector));
string result=acml::json::dumps(任何_对象)

将成为:

{
    "string": "the-string-value",
    "map":
    {
        "key1": "val1",
        "key2": "val2"
    },
    "vector":
    {
        "type": "std::vector",
        "size": "4",
        "0": "1",
        "1": "2",
        "2": "3",
        "3": "4"
    }
}
如您所见,JSON数组尚未实现。
现在所有的东西都变成字符串。

< p>任何好的C++ JSON库都应该这样做,而且很遗憾地看到它们没有——除了和显然在这里提到的一样。

当然,C++没有像java那样的反射,所以必须显式注释你的类型:
(复制自ThorsSerializer文档)


<>你不能在C++中做得更好。 我编写了一个实验库,可以完成这项工作,但它需要对类结构和层次结构进行外部描述。它使用GCCXML构建xml字典,用于序列化反序列化:

目前这是一个实验项目,可以处理基本类型(int、float-double)、指向基本类型、类、继承成员等的指针。。。它实现了基本的std::vector ans std::map序列化,以及std::string实例

执行细节< /p> python脚本生成C++的POD类,每个JSON属性

有一个成员 您想要的是完全相反的东西,但是生成一个同时进行加载和保存的映射类却很简单

生成的代码依赖于一个外部json解析器库

您看过谷物()吗?它有JSON文件,用于使用C++对JSON进行序列化。

一个最小的开销(来自谷类)的例子可以在这里找到:S/

< P>如果问题仍然是实际的,那么看看库,一个小的头,只帮助在JSON表示和C++结构之间转换数据。 例如,具有以下结构:

struct message_source_t
{
  // Worker thread.
  std::int32_t m_thread_id;

  // Sender.
  std::string m_subsystem;
};

struct message_t
{
  // Who sent a message.
  message_source_t m_from;

  // When the message was sent (unixtime).
  std::tm m_when;

  // Message text.
  std::string m_text;
};
在json的帮助下,您可以创建以下json:

{
  "from" : 
    {
      "thread_id" : 4242,
      "sybsystem" : "json_dto"
    },
  "when" : "2016.09.28 19:55:00",
  "text" : "Hello world!"
}  
给定这样的JSON字符串,您可以将其转换为结构

你可以用

在中,我创建了一个非常有效的反射实现。它是为C++17编写的,与Visual Studio、g++和Clang一起使用。该库仅为标头,这意味着您只需将reflect和json标头复制到项目中即可使用它

JSON库只需要在REFLECT宏中列出一次字段;从那里,它自动识别用于读取或写入的适当JSON输出表示,并可以递归地遍历任何反射字段,以及数组、STL容器、引用、指针等

struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}
您还可以对字段进行注释,例如在JSON表示中为它们指定不同的名称,强制它们为字符串,等等

struct Point
{
    NOTE(latitude, Json::Name{"lat"})
    double latitude;

    NOTE(longitude, Json::Name{"long"})
    double longitude;

    REFLECT(Point, latitude, longitude)
};
有关更多示例,请参阅,还有许多其他功能,如捕获超类、支持读取、遍历和写入编译时未知的JSON、进一步自定义特定字段或类型的JSON表示等等。

允许您进行任意类型转换。这里更详细地描述了它

struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}
class Example {  
    std::string string;  
    std::map<std::string, std:string> map;  
    std::vector<int> vector;

    // Add this to your code.
    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Example, string, map, vector);
};
注意我是如何使用NLOHMANN\u DEFINE\u TYPE\u NON\u INTRUSIVE的,因为结构成员是公共的

现在我可以调用
to_json(json&j,const MyStruct&s)
函数,如下所示:

MyStruct s;
s.name = "test";
s.number = 11;

nlohmann::json j;
s.to_json(j, s);
std::cout << j << std::endl;
// {"name":"test","number":11}
MyStruct;
s、 name=“测试”;
s、 数字=11;
nlohmann::json j;
s、 to_json(j,s);
我是这本书的作者。你是正确的,C++在这个时候没有反射,它会很好地让简单的东西在路上。但通过定义一个简单的声明性映射,JSON链接将为您的类型提供一个类型检查解析器。例如,您指定的类可以映射为:

类示例{
std::字符串;
地图;
std::向量;
};
na
struct MyOtherObject { int myOtherInt; REFLECT(MyOtherObject, myOtherInt) };
struct MyObject
{
    int myInt;
    std::string myString;
    MyOtherObject myOtherObject;
    std::vector<int> myIntCollection;

    REFLECT(MyObject, myInt, myString, myOtherObject, myIntCollection)
};

int main()
{
    MyObject myObject = {};
    std::cout << "Enter MyObject:" << std::endl;
    std::cin >> Json::in(myObject);
    std::cout << std::endl << std::endl << "You entered:" << std::endl;
    std::cout << Json::pretty(myObject);
}
Enter MyObject:
{
  "myInt": 1337, "myString": "stringy", "myIntCollection": [2,4,6],
  "myOtherObject": {
    "myOtherInt": 9001
  }
}


You entered:
{
  "myInt": 1337,
  "myString": "stringy",
  "myOtherObject": {
    "myOtherInt": 9001
  },
  "myIntCollection": [ 2, 4, 6 ]
}
struct Point
{
    NOTE(latitude, Json::Name{"lat"})
    double latitude;

    NOTE(longitude, Json::Name{"long"})
    double longitude;

    REFLECT(Point, latitude, longitude)
};
class Example {  
    std::string string;  
    std::map<std::string, std:string> map;  
    std::vector<int> vector;

    // Add this to your code.
    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Example, string, map, vector);
};
struct MyStruct {
    std::string name;
    int number;

    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MyStruct, name, number);
};
MyStruct s;
s.name = "test";
s.number = 11;

nlohmann::json j;
s.to_json(j, s);
std::cout << j << std::endl;
// {"name":"test","number":11}