Basically what I am saying is - you need to place more abstraction between your code and the end-user API.
Take this line:
std::string sayMessage = payload["message"].template get<std::string>();
Why not make a templated getString<“message”> that pulls from payload? So that would instead just be:
auto sayMessage = payload[“message”].as_string() or
auto sayMessage = payload.getString<“message”>() or
std::string sayMessage = payload[“message”] //We infer type from the assignment!!
It’s way cleaner. Way more effective. Way more intuitive.
When working on this kind of stuff end-developer experience should always drive the process. Look at your JSON library. Well known and loved. Imagine if instead of:
message[“code”] = “JOIN”; it was instead something like:
message.template set<std::string, std::string>(“CODE”, “JOIN”);
Somehow I don’t think the latter would have seen any level of meaningful adoption. It’s weird, obtuse and overly complex. You need to hide all that.