Я использую следующий шаблон для реализации сериализации:
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);
}
Вот T
тип, который вы хотите сериализовать Mode
, это фиктивный тип, чтобы различать разные виды сериализации, например. одно и то же целое число может быть сериализовано как little-endian, big endian, varint и т. д.
По умолчанию Serializer
делегирует задачу сериализуемому объекту. Для встроенных типов вы должны сделать шаблон специализации Serializer
.
Удобные шаблоны функций также предоставляются.
Например, немного порядковый номер сериализации без знака целых чисел:
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++;
}
}
};
Затем сериализовать:
std::vector<char> serialized;
uint32_t val = 42;
serialize<LittleEndianMode>(val, std::back_inserter(serialized));
Для десериализации:
uint32_t val;
deserialize(val, serialized.begin(), serialized.end());
Из-за абстрактной логики итератора он должен работать с любым итератором (например, потоковыми итераторами), указателем и т. Д.