Here I demonstrate an interesting pattern I call “CompactSerializable” which is neat when you want the following:
- quick and easy to use initialization syntax
- your object needs to have multiple members
- your object needs to have have different types of members, which are not known at design time
- your object must not have members you will not use (occupy minimum memory)
We first declare template classes, each representing a “dimension”. While it might be weird to have multiple dimensions, each a different type, it’s simply the common nomenclature for vector/matrix objects, so not strictly representing an actual dimension. Good names would also have been “Layer” or “MemberNumber”, etc.
In this example we will only be using 3 dimensions.
template <typename T1> struct dimension1 {
dimension1<T1>() = default;
dimension1(T1 nx) : x(nx) {}
T1 x;
};
template <typename T1, typename T2> struct dimension2 : public dimension1<T1> {
dimension2<T1, T2>() = default;
dimension2(T1 nx, T2 ny) : dimension1<T1>(nx) , y(ny) {}
T2 y;
};
template <typename T1, typename T2, typename T3>
struct dimension3 : public dimension2<T1, T2> {
/*for the sake of verbosity we will leave default
constructors uninitialized*/
dimension3<T1, T2, T3>() = default;
dimension3(T1 nx, T2 ny, T3 nz) : dimension2<T1,T2>(nx,ny) , z(nz) {}
T3 z;
};
We then declare the object itself. The default constructor is deleted because the goal is to determine member type(s) via constructor initialization, so an null object wouldn’t make sense.
template <typename T> struct CompactSerializable {
CompactSerializable() = delete;
template <typename T1>
CompactSerializable(T1 nx) : value(nx) {}
template <typename T1, typename T2>
CompactSerializable(T1 nx, T2 ny) {
value.x = nx;
value.y = ny;
}
template <typename T1, typename T2, typename T3>
CompactSerializable(T1 nx, T2 ny, T3 nz) {
value.x = nx;
value.y = ny;
value.z = nz;
}
T value;
};
Finally, we use template deduction guides to instantiate the object with the right sized dimension.
template <typename T1>
CompactSerializable(T1) ->
CompactSerializable<dimension1<T1>>;
template <typename T1, typename T2>
CompactSerializable(T1, T2) ->
CompactSerializable<dimension2<T1, T2>>;
template <typename T1, typename T2, typename T3>
CompactSerializable(T1, T2, T3) ->
CompactSerializable<dimension3<T1, T2, T3>>;
If we want to quickly serialize some object one after another, we can do it!
Usage:
CompactSeralizable obj1(
Foo(5),
Bar(6, "pretty"));
SeralizeAndSendOverNetwork(obj1);
CompactSeralizable obj2(
*ptrToComplexObject,
AdditionalInfo(100, "test"),
Foo(1024));
SeralizeAndSendOverNetwork(obj2);
There would of course have to be functions written for serializing each of the possible object types, as are commonly written anyway.
Leave a Reply