So I have owned a library for 6years or so that does constexpr JSON to data structures, JSON Link. There are a few benefits and in the near future with #embed it gets even better. The big benefit is that we can now get earlier errors and do testing in constexpr that gives more guarantees around the areas of core UB and in most implementations they add constexpr checked preconditions on the std library too. But, just because it is marked constexpr, doesn't mean it will be run at compile time. This also, limits the shenanigans that the library dev can do to get potential perf and work around design limitations.
In JSON Link's case, since it was using C++17 at the time, it forced me to think around the problem of allocation and who does it. The library does not allocate, but potentially the data structures being deserialized to will. In C++20 you can get limited constexpr allocations but they are good for things like stacks and eliminating the fixed buffers many devs have used in the past; which is a good thing on it's own but isn't really allowing one to parse to a vector at compile time(as in OP's example) for things that persist.
Where this will get really interesting, though, is when #embed is in the major compilers. It's mostly there in clang, with gcc on the way I believe. It will open the door for DSL's and compile time configs in human readable formats or interop with other tools(maybe GUI designers)
As for OP's library, I am not a fan of the json_value like library approach that treats JSON as a thing to care about when it is usually just an imp detail to move to ones business objects.
TL;DR
The big benefit though, is the ability to reason about the quality of the code in the library and have stronger testing.
That's a slightly more interesting use case. But "detect data errors at code compile-time via ultra complex comptime template metaprogramming" does not strike me as a particularly good idea. There are much better, easier ways to detect data errors. And the value of baking JSON data into an executable (even if it's transformed) is highly suspect imho.
Whether or not this is useful (I am also not sure), the JSON doesn't need to survive into runtime at all. If you include the JSON, do a bunch of `if constexpr`, and never touch the JSON outside of a constexpr context, it doesn't have to any footprint on your binary. (I'm not sure if #embed will force stuff to stay in your binary even if you never reference it at runtime)
Since you've done this for real in a library, I have to ask: how would you decide to use a compile-time template solution like this versus a code generator or some other "outboard" tool to generate code?
I'm curious since I've gone back and forth on this in my own career. Both approaches come with their own pros and cons, but each get us to the same place.
I def have more experience with the compile time and it's big issue is how long it can take, but I think it can be overblown on the cost too. However, one can often mitigate this with good code separation and firewalling. The compile time methods will never(probably) be faster than generated code in the C++ compiler. But, a TU with a simple function like `Config parse_config( std::string_view json_doc );` can protect the other code and reduce the general compile time when working on the real code. I think both have their debugging issue with codegen being difficult to tie to the source and the compile time parts relying on the limited error facilities available currently. The proposed p2471 - https://wg21.link/p2471 should help with this a lot and allow for non-literal static_assert messages.
One place I have used the compile time, since JSON Link uses declarative mappings and is type based, is allowing for automatic (de)serialization of function calls over RPC/IPC. This makes things like communicating with web engines really neat, or doing serialized RPC calls over some other mechanism. Code like `server.register( "path", [] ( int x, Foo foo ) { ... } );` is working now in C++, and that's really neat and closely analogues some of the higher level API's in other languages.
You're right to point out that this is really 'first class JSON', rather than the Pydantic/Jackson type thing where the json barely exists and is immediately transformed into your models and classes.
Thanks for reading the article though, that's cool. I am a daw_json_link fan
Build up the test suite inside static asserts, or a macro that lets you switch. It will be really nice when you update right and your IDE will tell you before you even hit compile because clangd found an issue.
In JSON Link's case, since it was using C++17 at the time, it forced me to think around the problem of allocation and who does it. The library does not allocate, but potentially the data structures being deserialized to will. In C++20 you can get limited constexpr allocations but they are good for things like stacks and eliminating the fixed buffers many devs have used in the past; which is a good thing on it's own but isn't really allowing one to parse to a vector at compile time(as in OP's example) for things that persist.
Where this will get really interesting, though, is when #embed is in the major compilers. It's mostly there in clang, with gcc on the way I believe. It will open the door for DSL's and compile time configs in human readable formats or interop with other tools(maybe GUI designers)
As for OP's library, I am not a fan of the json_value like library approach that treats JSON as a thing to care about when it is usually just an imp detail to move to ones business objects.
TL;DR The big benefit though, is the ability to reason about the quality of the code in the library and have stronger testing.