C++结构体和JSON字符串之间的相互转换
json
适用于现代 C++ 的 JSON。
项目地址:https://gitcode.com/gh_mirrors/js/json
免费下载资源
·
搞了份代码,在VS2013下运行通过。
有的时候,我们需要对C++的结构体进行JSON化,有的时候,我们又需要把JSON字符串转换成C++结构体,先看下面的代码
struct TestStruct
{
string strMember1;
float fMember2;
double fMember3;
};
TOJSON(TestStruct, v.strMember1, v.fMember2);
void main()
{
//下面代码是将C++结构体转换成JSON
TestStruct test1;
test1.strMember1 = "I am member1";
test1.fMember2 = 2.0f;
test1.fMember3 = 3.0;
string_stream ss;
save_to(ss, test1);
cout << ss.str() << "\n" << endl;
//下面代码是将JSON转换成C++结构体
std::string strJson = "\{\"strMember1\":\"I am json member 1\",\"fMember2\":-2\}";
TestStruct test2;
load_from_buff(test2, (char *)strJson.c_str());
int kk = 0;
std::cin >> kk;
}
这段代码会在屏幕上显示{"strMember1":"I am member1","fMember2":2} 如果你在最后一行打个断点。观察test2的值,将会发现其第一个成员的值是
“I am json member" 第二个成员的值是-2
这是怎么实现的呢?这需要使用C++的模板类
先看json转换成C++结构体 load_from_buf的代码如下
template<typename ty>
inline void load_from_buff(ty& val, char * buff, size_t len = -1)
{
reader rd(buff, len);
json_impl<ty>::read(rd, val);
}
reader类只是提供一些帮助解析的函数。
json_impl负责具体的干活。先来看一下。浮点数的成员变量如何处理。代码如下
template<typename ty, class enable = void>
struct json_impl;
template<typename ty>
struct json_impl < ty,
typename std::enable_if <std::is_floating_point<ty>::value>::type >
{
static inline void read(reader& rd, ty& val)
{
auto& tok = rd.peek();
switch (tok.type)
{
case token::t_string:
{
double temp = std::strtold(tok.str.str, nullptr);
val = static_cast<ty>(temp);
break;
}
case token::t_int:
{
val = static_cast<ty>(tok.value.i64);
break;
}
case token::t_uint:
{
val = static_cast<ty>(tok.value.u64);
break;
}
case token::t_number:
{
val = static_cast<ty>(tok.value.d64);
break;
}
default:
{
rd.error("not a valid float point number.");
}
}
rd.next();
}
template<typename write_ty>
static inline void write(write_ty& wt, ty const& val)
{
char buffer[64] = { 0 };
#ifdef _MSC_VER
_gcvt_s(buffer, 63, val, 8);
#else
gcvt(val, 62, buffer);
#endif // MSVC
size_t len = std::strlen(buffer);
if (buffer[len - 1] == '.')
{
buffer[len - 1] = '\0';
--len;
}
wt.write_liter(buffer, len);
}
template<typename write_ty>
static inline void write_key(write_ty& wt, ty const& val)
{
wt.putc('"');
write<write_ty>(wt, val);
wt.putc('"');
}
};
接着就是最关键的宏,依次读出结构体的成员名字
#define TOJSON(TYPE,...) \
namespace ajson{\
template<> \
struct json_impl < TYPE, void > \
{ \
static inline detail::filed_list& this_filed_list() \
{\
static auto fields = detail::split_fields(STRINGFY_LIST(__VA_ARGS__)); \
return fields; \
}\
static inline void read(reader& rd, TYPE& v) \
{ \
auto& fields = this_filed_list(); \
if (rd.expect('{') == false){ rd.error("read object must start with {!"); } \
rd.next(); \
if (rd.expect('}')) \
return; \
auto mber = rd.peek(); \
size_t pos = 0; \
do \
{ \
if (mber.type != token::t_string){ rd.error("object key must be string"); } \
rd.next(); \
if (rd.expect(':') == false){ rd.error("invalid json document!"); } \
rd.next(); \
if (read_members(rd, &fields[0], mber.str, 0, __VA_ARGS__) == 0) \
{ \
skip(rd); \
} \
if (rd.expect('}')) \
{ \
rd.next(); \
return; \
} \
else if (rd.expect(',')) \
{ \
rd.next(); \
mber = rd.peek(); \
continue; \
} \
rd.error("invalid json document!"); \
} while (true); \
} \
template<typename write_ty>\
static inline void write(write_ty& wt, TYPE const& v)\
{\
auto& fields = this_filed_list(); \
wt.putc('{'); \
::ajson::write_members(wt, &fields[0], 0, __VA_ARGS__); \
wt.putc('}'); \
}\
}; \
}
整个原理就是这个样子了。
当然宏定义也可以放在结构体的内部,但是这样就不得不对结构体进行改变,不过这样的好处是可以检测是否有遗漏的结构体项,在特殊需求下可以使用。另外如果不想改变现有的任何代码,可以使用PDB文件。PDB文件里当然有所有类成员的名字,坏处就是无法进行编译检查(http://github.com/lumpyzhu/nmscc的观点,我只是引用)
有了整个原理,相信大家都不难实现出完整的代码。(有兴趣的同学可以每个方案都实现一下)。
如果对实现的原理还有任何疑问,欢迎交流探讨!
GitHub 加速计划 / js / json
18
5
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:3 个月前 )
f06604fc
* :page_facing_up: bump the copyright years
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* :page_facing_up: bump the copyright years
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* :page_facing_up: bump the copyright years
Signed-off-by: Niels Lohmann <niels.lohmann@gmail.com>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
Signed-off-by: Niels Lohmann <niels.lohmann@gmail.com> 3 天前
d23291ba
* add a ci step for Json_Diagnostic_Positions
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* Update ci.cmake to address review comments
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* address review comment
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix typo in the comment
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix typos in ci.cmake
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* invoke the new ci step from ubuntu.yml
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* issue4561 - use diagnostic positions for exceptions
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix ci_test_documentation check
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* address review comments
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix ci check failures for unit-diagnostic-postions.cpp
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* improvements based on review comments
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix const correctness string
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* further refinements based on reviews
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* add one more test case for full coverage
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* ci check fix - add const
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* add unit tests for json_diagnostic_postions only
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix ci_test_diagnostics
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
* fix ci_test_build_documentation check
Signed-off-by: Harinath Nampally <harinath922@gmail.com>
---------
Signed-off-by: Harinath Nampally <harinath922@gmail.com> 4 天前
更多推荐
已为社区贡献1条内容
所有评论(0)