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.