Ich verwende die folgende Vorlage, um die Serialisierung zu implementieren:
template <class T, class Mode = void> struct Serializer
{
template <class OutputCharIterator>
static void serializeImpl(const T &object, OutputCharIterator &&it)
{
object.template serializeThis<Mode>(it);
}
template <class InputCharIterator>
static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
{
return T::template deserializeFrom<Mode>(it, end);
}
};
template <class Mode = void, class T, class OutputCharIterator>
void serialize(const T &object, OutputCharIterator &&it)
{
Serializer<T, Mode>::serializeImpl(object, it);
}
template <class T, class Mode = void, class InputCharIterator>
T deserialize(InputCharIterator &&it, InputCharIterator &&end)
{
return Serializer<T, Mode>::deserializeImpl(it, end);
}
template <class Mode = void, class T, class InputCharIterator>
void deserialize(T &result, InputCharIterator &&it, InputCharIterator &&end)
{
result = Serializer<T, Mode>::deserializeImpl(it, end);
}
Hier T
ist der Typ, den Sie serialisieren möchten, Mode
ein Dummy-Typ, um zwischen verschiedenen Arten der Serialisierung zu unterscheiden, z. Die gleiche Ganzzahl kann als Little Endian, Big Endian, Varint usw. serialisiert werden.
Standardmäßig Serializer
delegiert die Aufgabe an das zu serialisierende Objekt. Für eingebaute Typen sollten Sie eine Vorlagenspezialisierung der vornehmen Serializer
.
Vorlagen für Komfortfunktionen werden ebenfalls bereitgestellt.
Zum Beispiel Little-Endian-Serialisierung von Ganzzahlen ohne Vorzeichen:
struct LittleEndianMode
{
};
template <class T>
struct Serializer<
T, std::enable_if_t<std::is_unsigned<T>::value, LittleEndianMode>>
{
template <class InputCharIterator>
static T deserializeImpl(InputCharIterator &&it, InputCharIterator &&end)
{
T res = 0;
for (size_t i = 0; i < sizeof(T); i++)
{
if (it == end) break;
res |= static_cast<T>(*it) << (CHAR_BIT * i);
it++;
}
return res;
}
template <class OutputCharIterator>
static void serializeImpl(T number, OutputCharIterator &&it)
{
for (size_t i = 0; i < sizeof(T); i++)
{
*it = (number >> (CHAR_BIT * i)) & 0xFF;
it++;
}
}
};
Dann zu serialisieren:
std::vector<char> serialized;
uint32_t val = 42;
serialize<LittleEndianMode>(val, std::back_inserter(serialized));
Deserialisieren:
uint32_t val;
deserialize(val, serialized.begin(), serialized.end());
Aufgrund der abstrakten Iteratorlogik sollte es mit jedem Iterator (z. B. Stream-Iteratoren), Zeiger usw. funktionieren.