























https://blog.csdn.net/kpengk/article/details/118070178
序列化是编程中一个非常实用的技术,它能够将对象转换为可以存储或传输的格式,而反序列化则是将这种格式重新转换为对象的过程。今天,我将分享如何利用C++的模板元编程技术来实现一个简单而强大的序列化库。
想象一下,你需要将一个C++对象保存到文件中,或者通过网络发送给另一台计算机。序列化就是将对象转换为字节流的过程,而反序列化则是将这些字节流重新构建为原始对象。
本文实现的序列化库支持以下数据类型:
基本类型:char、short、int、long、float、double以及无符号整数;
字符串:std::string;
向量:std::vector,支持vector<基本类型>、vector<字符串>及vector<struct>;
嵌套结构:支持复杂的嵌套数据结构。
模板元编程(Template Metaprogramming,TMP)是C++中一种在编译期执行计算的技术。它利用模板特化、递归实例化等机制,在编译期间生成代码,从而实现类型安全的通用编程。
在我们的序列化库中,模板元编程主要体现在以下几个方面:
编译期类型判断:使用 std::is_class_v在编译期判断类型是否为类类型。
模板特化:为不同类型提供特定的序列化实现。
递归模板:处理可变参数和嵌套结构。
类型分发是序列化库的核心技术,它根据不同的类型选择不同的序列化策略:
template <bool cond, typename T> class IF { // 类类型的序列化策略 }; template <typename T> class IF<false, T> { // 基本类型的序列化策略 }; template <typename T> inline size_t valsize(const T& val) { return IF<std::is_class_v<T>, T>::_val_size(val); }
这种设计实现了:
我们的序列化数据包采用简单的结构:
---------------------- | 包长度 | 数据 | |---------------------| | int | char[] | ----------------------
这种设计具有以下优点:

这种编码规则确保了:
// Serialization.hpp /* 序列化说明 * 1.包组成: * ----------------------- * | 包长度 | 数据 | * |-----------------------| * | int | char[] | * ----------------------- * 2.数据组成 * ------------------------------------------------------------------------------------- * | 类型 | 符号表示 | 排列方式,其中len(x)的类型为unsigned int | * |-------------------------------------------------------------------------------------| * | 基本类型 | T | T | * | 字符串 | S | len(S) + S | * | 基本类型向量 | V<T> | len(V) + T1 + T2 + T3 + ... + Tn | * | 字符串向量 | V<S> | len(V) + len(S1) + S1 + len(S2) + S2 + ... + len(Sn) + Sn | * ------------------------------------------------------------------------------------- */ #ifndef SERIALLIZATION_H_ #define SERIALLIZATION_H_ #include <string> #include <vector> #define DEFINE_PACK(...) \ public: \ size_t pack_size() const { \ return sizeof(int) + Ser::all_size(__VA_ARGS__); \ } \ std::string to_string() const { \ const size_t _count = sizeof(int) + Ser::all_size(__VA_ARGS__); \ std::string _result; \ _result.reserve(_count); \ Ser::push(_result, (int) _count); \ Ser::pack(_result, __VA_ARGS__); \ return _result; \ } \ bool from_string(const char* const _buf, const int _len) { \ if (_len < sizeof(int)) \ return false; \ const char* _ptr = _buf; \ int _count = 0; \ Ser::take(_count, _ptr); \ if (_count != _len) \ return false; \ Ser::unpack(_ptr, __VA_ARGS__); \ return true; \ } \ bool from_string(const std::string& _buf) { \ return from_string(_buf.data(), _buf.size()); \ } namespace Ser { template <bool cond, typename T> class IF { public: static inline size_t _val_size(const T& val) { return val.pack_size(); } static inline void _push(std::string& buf, const T& val) { buf.append(val.to_string()); } static inline void _take(T& val, const char*& buf) { const int count = *(reinterpret_cast<const int*>(buf)); val.from_string(buf, count); buf += count; } }; template <typename T> class IF<false, T> { public: static inline size_t _val_size(const T& val) { return sizeof(T); } static inline void _push(std::string& buf, const T& val) { const char* ptr = reinterpret_cast<const char*>(&val); buf.append(ptr, sizeof(T)); } static inline void _take(T& val, const char*& buf) { val = *(reinterpret_cast<const T*>(buf)); buf += sizeof(T); } }; /* 计算单个元素序列化后的长度 */ template <typename T> inline size_t valsize(const T& val) { return IF<std::is_class_v<T>, T>::_val_size(val); } template <> inline size_t valsize<std::string>(const std::string& val) { return sizeof(unsigned int) + val.size(); } template <typename T> size_t valsize(const std::vector<T>& val) { size_t len = sizeof(unsigned int); for (size_t i = 0; i < val.size(); ++i) { len += valsize(val[i]); } return len; } /* 序列化单个元素 */ template <typename T> inline void push(std::string& buf, const T& val) { IF<std::is_class_v<T>, T>::_push(buf, val); } template <> inline void push<std::string>(std::string& buf, const std::string& val) { const unsigned int len = static_cast<unsigned int>(val.size()); buf.append(reinterpret_cast<const char*>(&len), sizeof(unsigned int)); buf.append(val); } template <typename T> void push(std::string& buf, const std::vector<T>& val) { const unsigned int len = static_cast<unsigned int>(val.size()); push(buf, len); for (unsigned int i = 0; i < len; ++i) { push(buf, val[i]); } } /* 反序列化单个元素 */ template <typename T> inline void take(T& val, const char*& buf) { IF<std::is_class_v<T>, T>::_take(val, buf); } template <> inline void take<std::string>(std::string& val, const char*& buf) { unsigned int len = 0; take(len, buf); val.clear(); val.append(buf, len); buf += len; } template <typename T> void take(std::vector<T>& val, const char*& buf) { unsigned int len = 0; take(len, buf); val.resize(len); for (unsigned int i = 0; i < len; ++i) { take(val[i], buf); } } /* 计算不定参序列化后总长度 */ template <typename T> size_t all_size(const T& elem) { return valsize(elem); } template <typename T, typename... Args> size_t all_size(const T& elem, const Args&... args) { return valsize(elem) + all_size(args...); } /* 不定参序列化 */ template <typename T> void pack(std::string& buf, const T& elem) { push(buf, elem); } template <typename T, typename... Args> void pack(std::string& buf, const T& elem, const Args&... args) { push(buf, elem); pack(buf, args...); } /* 不定参反序列化 */ template <typename T> void unpack(const char*& buf, T& elem) { take(elem, buf); } template <typename T, typename... Args> void unpack(const char*& buf, T& elem, Args&... args) { take(elem, buf); unpack(buf, args...); } } // namespace Ser #endif /* SERIALLIZATION_HPP_ */
#include "Serialization.hpp" class Message { public: std::string type; // 类型 std::string msg; // 内容 int priority; // 优先级 long long id; // 序号 std::string ip; // IP DEFINE_PACK(type, msg, priority, id, ip) }; int main() { Message m = { "type", "test", 2, 56, "192.168.0.2" }; // 序列化 std::string buf = m.to_string(); // 反序列化 Message res; res.from_string(buf); return 0; }
#include "Serialization.hpp" class Base { public: std::string name; int id; std::vector<double> values; DEFINE_PACK(name, id, values) }; class FullInfo { public: std::string name; float val; std::vector<std::vector<Base>> vec; DEFINE_PACK(name, val, vec) }; int main() { FullInfo obj; obj.name = "Hello"; obj.val = 3.14F; obj.vec = { { {"elem 1", 1, {1.1, 1.2, 1.3, 1.4}}, {"elem 2", 2, {2.1, 2.2}}, {"elem 3", 3, {3.1, 3.2, 3.3}} }, { {"elem 4", 4, {4.1, 4.2, 4.3, 4.4}}, {"elem 5", 5, {5.1, 5.2}}, {"elem 6", 6, {6.1, 6.2, 6.3, 6.4, 6.5}} } }; // 序列化 const std::string buf = obj.to_string(); // 反序列化 FullInfo res{}; res.from_string(buf); return 0; }
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。