C++17 has simplified use of template parameters. Instructions, given in this tutorial, describes how to define
JSON model with cojson::autos templates.
Note: GCC 7 or higher is required to compile cojson_autos.hpp !
1. Defining Model
JSON model is defined as a template function, with pointers to all serializable members as the template parameters.
Everything else - JSON property name, data type, array extents, is deduced from pointer-to-member by cojson::autos templates.
cojson::autos defines two groups of template functions each having its specific purpose and name:
O<class,...>() | Object<class, ...>() | Defines an object mapped to a C++ class |
---|---|---|
P<auto,auto>() | Property<auto,auto>() | Defines an object property, bound to getter/setter or to an inner object |
struct MyClass { int Int; } obj; O<MyClass,&MyClass::Int>().read(obj, in);
1.1. Objects
Class-bound objects are defined with variadic template O<...> that accepts bounding class as the first parameter followed by the list of member pointers, method pointers or P templates.
1.2. Names
cojson::autos templates deduce names from the identifiers. E.g. member Int will be mapped to JSON property "Int". In a case, when this approach is not suitable, a cojson::P template should be used to define a property with an alternate name.
2. Scalar properties
2.1. Members
A class's member is referred by its pointer to member, e.g. &MyClass::Int
2.2. Methods
A property, mapped to a single getter or setter is referred by its pointer to method, e.g. &MyClass::setLatch. A property, that needs two methods - getter and setter, is defined by cojson::autos::P template, e.g. P<&MyClass::getLatch, &MyClass::setLatch>.
2.3. Immutable String
Immutable zero-terminated strings of unspecified length can be provided:
- by a pointer to (const) member of const char*
- by a pointer to method returning const char*
- by template PropertyStaticString with the class and a pointer to static member of const char*
- by template PropertyFunctionString with the class and a pointer to static method returning const char*
struct MyClass { const char* const a = "a"; const char* b() const noexcept { return "b"; } static const char* const c; static const char* d() noexcept { return "d"; } }; O<MyClass, &MyClass::a, &MyClass::b, PropertyStaticString<MyClass, &MyClass::c>, PropertyFunctionString<MyClass, &MyClass::d> >();
2.4. Mutable String Members
Mutable strings can be bound to
- a string of predefined capacity (char[N]) by a pointer to member.
- std::string by a pointer to member.
#include <string> #include <cojson_stdlib.hpp> //support for std::string properties struct MyClass { char msg[32]; std::string str; }; O<MyClass, &MyClass::msg, &MyClass::str>();
3. Nested Objects
Nested objects are mapped to a member of a class that has its own json model by using P template with pointer to member and pointer to method or function returning its model.
struct Outer { bool Bool; struct Inner { int Int; } obj; }; O<Outer, &Outer::Bool, P<&Outer::obj, O<Outer::Inner, &Outer::Inner::Int>>>();
4. Arrays
4.1. Vectors - arrays of integral values
Vectors are bound by a pointer to member of an array type or std::vector type
#include <vector> #include <cojson_stdlib.hpp> //support for std::vector properties struct MyClass { int vector[3]; std::vector<int> stdvect; }; O<MyClass, &MyClass::vector, &MyClass::stdvect>();
4.2. Strings - arrays of string values
String arrays are bound by a pointer to member of a two-dimensional array type (char[N][M]) or to a std::vector<std::string>
struct MyClass { int strings[3][32]; std::vector<std::string> stdstrings; }; O<MyClass, &MyClass::strings, &MyClass::stdstrings>();
4.3. Arrays of Objects
Similarly to nested objects, arrays of objects are mapped to an array member (or std::vector) of a class that has its own json model by using P template with pointer to member and pointer to method or function returning its model.
struct Outer { bool Bool; struct Inner { int Int; } objs[4]; std::vector<Inner> Objs; }; O<Outer, &Outer::Bool, P<&Outer::objs, O<Inner, &Inner:Int>>>(); O<Outer, &Outer::Bool, P<&Outer::Objs, O<Inner, &Inner:Int>>>();
4.4. Lists - arrays of heterogeneous values
cojson is designed to work with a predefined structure and this design imposes certain limitation on arrays - a heterogeneous array (ordered list) must have each of its item defined, fixed to a given type and bound to a given member. A list is defined with PropertyList template.
struct MyClass { int list; bool next; char last[32]; }; Object<MyClass, PropertyList<&MyClass::list, &MyClass::next, &MyClass::last>>();This will correspond to the following json:
{"list":[0, false, ""]}
5. Reading/Writing
5.1. Via std::iostream or similar
cojson::wrapper namespace provides template wrappers for C++ streams: istream and ostream, for reading and writing respectively. They require the wrapped streams to provide get(char) good() eof() / put(char) good() and can wrap almost any of the stdlib streams.
struct MyClass { int Int; } obj; cojson::wrapper::istream<std::istream> in(cin); cojson::wrapper::ostream<std::ostream> out(cout); O<MyClass,&MyClass::Int>().read(obj, in); O<MyClass,&MyClass::Int>().write(obj, out);
5.2. With operator<< operator>>
cojson::operator namespace provides template operators operator<< / operator>>. These templates require the class to implement either json() method or read(cojson::details::lexer&)/write(cojson::details::ostream&)
#include <cojson_stdlib.hpp> using namespace std; using namespace cojson; using namespace cojson::autos; using namespace cojson::operators; struct MyClass { int Int; static inline const auto& json() noexcept { return O<MyClass,&MyClass::Int>(); } } obj; cin >> obj; cout << obj << endl;
5.3. Via a memory buffer
cojson::wrapper namespace provides wrappers for memory buffers: buffer and memstream. Both read from and write to a single memory block. memstream maintains two separate position pointers while buffer maintains only one. When no writing is needed, buffer may by supplied with a constant zero-delimited string.
#include <cojson_stdlib.hpp> using namespace cojson; using namespace cojson::autos; struct Pdo { int Int; static inline const auto& json() noexcept { return O<Pdo,&Pdo::Int>(); } inline int read(const char* data) noexcept { wrapper::buffer input(data); details::lexer in(input); return json().read(*this, in) ? input.count() : -1; } inline int write(char* data, cojson::size_t size) noexcept { wrapper::buffer output(data, size); return json().write(*this, output) ? output.count() : -1; } };
5.4. Via a user-defined reader/writer
Please refer to COJSON tutorial Section 5.1 and Section 5.2 for details.
Post a Comment