July 6th, 2024

Compile-time JSON deserialization in C++

This article explores compile-time JSON deserialization in C++. It discusses static reflection, pattern matching, template specialization, and constexpr functions to parse JSON data into atomic and compound types, ensuring type safety and flexibility.

Read original articleLink Icon
Compile-time JSON deserialization in C++

This article discusses compile-time JSON deserialization in C++. The author explores the use of static reflection and pattern matching in modern C++ to handle JSON in a type-safe manner. By leveraging template specialization and constexpr functions, the author demonstrates how to parse JSON data into atomic and compound types. Atomic types like bool, string, and null are handled through template specializations with consumeFromJSON functions. Compound types such as arrays and objects are parsed recursively, ensuring type safety and flexibility in handling JSON structures. The article also delves into the challenges of indexing objects and dealing with nullable types in JSON parsing. Overall, the author showcases a methodical approach to automatically structuring JSON data in C++ using compile-time techniques, enabling developers to handle evolving JSON structures efficiently and with type safety.

Related

Weekend projects: getting silly with C

Weekend projects: getting silly with C

The C programming language's simplicity and expressiveness, despite quirks, influence other languages. Unconventional code structures showcase creativity and flexibility, promoting unique coding practices. Subscription for related content is encouraged.

Reflection for C++26

Reflection for C++26

The P2996R4 document proposes a reduced set of static reflection features in C++26, using constant expressions, a reflection operator, metafunctions, and splicers. Implementation progress is ongoing by Lock3 and EDG.

The Byte Order Fiasco

The Byte Order Fiasco

Handling endianness in C/C++ programming poses challenges, emphasizing correct integer deserialization to prevent undefined behavior. Adherence to the C standard is crucial to avoid unexpected compiler optimizations. Code examples demonstrate proper deserialization techniques using masking and shifting for system compatibility. Mastery of these concepts is vital for robust C code, despite available APIs for byte swapping.

I _____ hate arrays in C++

I _____ hate arrays in C++

The article explores challenges in using arrays in C++, focusing on array-to-pointer conversion pitfalls, differences from pointers, and practical examples of errors. Caution and awareness are advised for C++ developers.

A Type for Overload Set

A Type for Overload Set

The article explores C++ overload set challenges, discussing issues with standard functions encountering problems due to overloading. It introduces proposal P3312 for a unique type to address these limitations, emphasizing the need for a more efficient solution.

Link Icon 9 comments
By @nikki93 - 7 months
I use this static reflection hack in C++ -- https://godbolt.org/z/enh8za4ja

You do have to tag struct fields with a macro, but you can attach contexpr-visitable attributes. There's also a static limit to how many reflectable fields you can have, all reflectable fields need to be at the front of the struct, and the struct needs to be an aggregate.

By @stephc_int13 - 7 months
I am afraid of the compile-time cost.

For this kind of things I tend to prefer using a simpler program (written in anything you like) to generate C or C++ instead of having the compile do the same thing much slowly.

Meta programming can be good, but it is even better done with an actual meta program, IMO.

By @dctwin - 7 months
Hello! I wrote this short blog post about using pattern-matching-like template metaprogramming to deserialize JSON at build time - please let me know what you think (especially if you see improvements)
By @nikeee - 7 months
Could this be leveraged to emit a parser that is specialized for the provided type that can be used at runtime? Afaik .NET does something like that using code generators.

The advantage being that the parser is tailored to the specific type that is deserialized and it writes directly to the struct's fields instead of going through some dictionary.

By @abbeyj - 7 months
Could you use something like `template <StringLiteral str> constexpr inline Key<str> key;`? Then you could write `key<"myKey">` instead of `Key<"myKey">{}`, saving you from needing the `{}` each time.
By @fsloth - 7 months
What a beautiful example of abuse of C++ templates. I love it.

But please don’t do this in production.

What ever you need to do, use C++ templates as the last resort because you’ve figured out all other approaches suck even more. Maintaining template heavy code is absolutely horrible and wasteful (and if it’s C++ production code we measure it’s lifetime in decades). And no, there is no way ”to do it correctly so it doesn’t suck”.

Templates belong to the lowest abstraction levels - as stl mostly does. Anyhting more prevalent is an abomination.

If the schema is fixed, have types with the data and if you have a default data, provide it using initializer lists.

Ie. have a struct or structs with explicit serializeToJson and deserializeFromJson functions.

It’s faster to write than figuring out the correct template gymnastics and about 100x easier to maintain and extend.

By @actionfromafar - 7 months
Where are the functional language programmers so I can hold their beer?
By @anothername12 - 7 months
Not a C++ user, but is this the same as #. reader macro in Common Lisp?
By @forrestthewoods - 7 months
I think the value of compile-time JSON deserialization is... well I was going to say zero but really it's negative. It's a cute trick, but please don't ever do this in a real project.