I have to write a very basic JSON serializer/deserializer in C++. The goal is to build something similar to this https://github.com/nlohmann/json. Unfortunately I can't use this awesome library because my compiler does not fully support the C++ 11 standard. Switching the compiler is not an option.
I would like to go with an approach close to the following examples. I am writing my idea in some sort of pseudo code, based on the TypeScript Syntax.
I'm imaging a class representing a JSON object, with functions to access it's keys and get some dynamic values from them.
type JSONValue = int | double | string | list | JSONObject | ...;
class JSONObject {
private map: Map<string, JSONValue>;
public set(key: string, value: JSONValue) { ... };
public get(key: string): JSONValue { ... };
public stringify(): string;
}
I think the general concept should be clear. Parsing a JSON string is not the problem. Creating a JSON string is trivial too. But creating a type like JSONValue
in C++ is something I can't wrap my head around.
Probably the way to go are templates, but I need some guidance on how to implement such a "dynamic" type. I would like to get some example on how to approach this problem.
Edit: The code has to work in RAD Studio 10.2.3 with the Clang enhanced compiler. It's hard to tell what this compiler supports so I will test every suggestion and add the limitations to this question as they arise.
Edit 2: Running bcc32x --version
yields the following results:
Embarcadero C++ 7.30 for Win32 Copyright (c) 2012-2017 Embarcadero Technologies, Inc.
Embarcadero Technologies Inc. bcc32x version 3.3.1 (36355.e71d049.f8c4cf9) (based on LLVM 3.3.1)
Target: i686-pc-win32-omf
Thread model: posix
In your case, you don't actually need fully dynamic typing, as JSONValue
can't have any type, just some amount of different types. This is what you would use a union
for:
union JSONValue {
long long integer;
double floating;
std::string string;
...
}
Unions of non-trivially destructible types are however quite unsafe, because you need to make sure that the destructor of string
gets called, if string
is the active member.
If you were using C++17, you could use std::variant
, which is essentially a type-safe union
. Before C++17 (in your case), boost::variant
can be used instead.