搞了份代码,在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 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐