当前位置: 首页 > news >正文

通用序列化和反序列化实现思路

本文简单的记录一下采用模板来实现序列化与反序列的思路, 同时采用C++20标准的concept和requires来简化模板函数的选择。

首先了解一下自定义类支持序列化的两种方式:

一、序列化自定义类型(侵入式)

struct Test {std::string name;int age;//序列化接口template<class Archive>void serialize(Archive & ar) const {ar & REFLEX(name);ar & REFLEX(age);}
};

二、序列化自定义类型(非侵入式)

struct Test2 {std::string name;int age;
};//序列化接口
template<class Archive>
void serialize(Archive & ar,const Test2& t) {ar & REFLEX(t.name);ar & REFLEX(t.age);
}

这种方法用于序列化一些外部库定义的类,或一些不希望修改实现的类。

接下来实现一个采用二进制方案的序列化类

//用于识别自定义类内部是否支持serialize函数
template<typename AR, typename V>
concept is_user_def_inside = requires(AR ar, V v) {v.serialize(ar);
};//用于识别自定义类外部是否支持了serialize函数
template<typename AR, typename V>
concept is_user_def_outside = requires(AR ar, V v) {serialize(ar, v);
};class ArchiveOut {
public:ArchiveOut(std::ostream& os):m_os(os){}using ArchiveTp = ArchiveValue;template<typename T>ArchiveOut& operator & (const T& val){this->operator<<(val);return *this;}//自定义类(侵入式)template<typename T>requires(is_user_def_inside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){val.serialize(*this);return *this;}// 可平凡复制 template<typename T>requires(std::is_trivially_copyable<T>::value)ArchiveOut& operator << (const T& val){m_os.write((const char *)&val, sizeof(T));return *this;}//自定义类(非侵入式)template<typename T>requires(!std::is_trivially_copyable<T>::value && !is_user_def_inside<ArchiveOut,T> && is_user_def_outside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){serialize(*this,  val);return *this;}//string 特化ArchiveOut& operator << (const std::string& val){size_t size = val.size();m_os.write((const char *)&size, sizeof(size));m_os.write((const char *)val.data(), size * sizeof(typename std::string::value_type));return *this;}//其它类型处理
private:std::ostream& m_os;
};

前文中的REFLEX为自定义宏, 用于生成诸如json、xml时,对字段名的反射, 因为基于二进制序列化的时候,可以只保存值,而不需要保存字段名,但生成json、xml等格式时需要用到字段名称,因此实现Reflex时,需要根据序列化类型字段选择。

#define REFLEX(param)  CReflex(param, #param)
#define REFLEX_ALIAS(param, alias) CReflex(param, alias)//只针对值进行序列化
enum class ArchiveValue {
};
//对字段名和值进行序列化
enum class ArchiveKeyValue {
};template<typename T>
concept is_key_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveKeyValue>::value;
};template<typename T>
concept is_only_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveValue>::value;
};template<typename T>
class CReflex {
public:CReflex(T& value, const std::string& strName) :m_value(value), m_name(strName) {};template<typename Archive>requires(is_only_value<Archive>)void serialize(Archive& ar)const {ar & m_value;}template<typename Archive>requires(!is_only_value<Archive> && is_key_value<Archive>)void serialize(Archive& ar)const {ar & (m_name, m_value);}
private:T& m_value;std::string m_name;
};

到这里一个大致的模型已经实现,当然,真正实施起来还有许多细节需要补充。

附完整代码:


#include <string>
#include <concepts>
#include <iostream> 
#include <sstream>
#include <type_traits>#define REFLEX(param)  CReflex(param, #param)
#define REFLEX_ALIAS(param, alias) CReflex(param, alias)//只针对值进行序列化
enum class ArchiveValue {
};
//对字段名和值进行序列化
enum class ArchiveKeyValue {
};template<typename T>
concept is_key_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveKeyValue>::value;
};template<typename T>
concept is_only_value = requires() {std::is_same<typename T::ArchiveTp, ArchiveValue>::value;
};template<typename T>
class CReflex {
public:CReflex(T& value, const std::string& strName) :m_value(value), m_name(strName) {};template<typename Archive>requires(is_only_value<Archive>)void serialize(Archive& ar)const {ar & m_value;}template<typename Archive>requires(!is_only_value<Archive> && is_key_value<Archive>)void serialize(Archive& ar)const {ar & (m_name, m_value);}
private:T& m_value;std::string m_name;
};template<typename T>
concept is_container = requires(T res, T::value_type v) {res.insert(res.begin(), v);
};template<typename AR, typename V>
concept is_user_def_inside = requires(AR ar, V v) {v.serialize(ar);
};template<typename AR, typename V>
concept is_user_def_outside = requires(AR ar, V v) {serialize(ar, v);
};class ArchiveOut {
public:ArchiveOut(std::ostream& os):m_os(os){}using ArchiveTp = ArchiveValue;template<typename T>ArchiveOut& operator & (const T& val){this->operator<<(val);return *this;}//自定义类(侵入式)template<typename T>requires(is_user_def_inside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){val.serialize(*this);return *this;}// 可平凡复制 template<typename T>requires(std::is_trivially_copyable<T>::value)ArchiveOut& operator << (const T& val){m_os.write((const char *)&val, sizeof(T));return *this;}//自定义类(非侵入式)template<typename T>requires(!std::is_trivially_copyable<T>::value && !is_user_def_inside<ArchiveOut,T> && is_user_def_outside<ArchiveOut,T>)ArchiveOut& operator << (const T& val){serialize(*this,  val);return *this;}//string 特化ArchiveOut& operator << (const std::string& val){size_t size = val.size();m_os.write((const char *)&size, sizeof(size));m_os.write((const char *)val.data(), size * sizeof(typename std::string::value_type));return *this;}//其它类型处理
private:std::ostream& m_os;
};struct Test {std::string name;int age;//序列化接口template<class Archive>void serialize(Archive & ar) const {ar & REFLEX(name);ar & REFLEX(age);}
};struct Test2 {std::string name;int age;
};//序列化接口
template<class Archive>
void serialize(Archive & ar,const Test2& t) {ar & REFLEX(t.name);ar & REFLEX(t.age);
}int main()
{Test t = {"zhangshan", 36};Test2 t2 = {"liubei", 38};std::ostringstream ss;ArchiveOut ar(ss);ar << t << t2;std::cout << "size : " << ss.str().length() << ", value: " << ss.str() << std::endl;return 0;
}

相关文章:

通用序列化和反序列化实现思路

本文简单的记录一下采用模板来实现序列化与反序列的思路&#xff0c; 同时采用C20标准的concept和requires来简化模板函数的选择。 首先了解一下自定义类支持序列化的两种方式&#xff1a; 一、序列化自定义类型&#xff08;侵入式&#xff09; struct Test {std::string na…...

书生营第四期L0G2000 Python 基础知识

闯关任务 Leetcode 383(笔记中提交代码与leetcode提交通过截图) class Solution:def canConstruct(self, ransomNote: str, magazine: str) -> bool:note [0]*26maga [0]*26for s in ransomNote:note[ord(s)-ord(a)] 1for s in magazine:maga[ord(s)-ord(a)] 1for i in…...

Day12-数据库服务冗余架构

Day-12-数据库服务高可用集群 1、数据库MGR组复制实践2、数据库高可用MHA应用介绍3、数据库高可用MHA环境准备4、数据库高可用MHA原理机制5、数据库高可用MHA功能配置 1、数据库MGR组复制实践 &#xff08;强一致性主从同步) 2、数据库高可用MHA应用介绍 3、数据库高可用MHA环境…...

js监听div尺寸,ResizeObserver

示例&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><style>.observedDiv {width: 40vw;height: 50vh;background-color: lightblue;}</style></head><body><div id"…...

STM32与openmv的串口通信

OpenMV与STM32的通信是嵌入式系统和物联网领域中的一项重要技术。OpenMV是一种开源的微型机器视觉模块&#xff0c;基于ARM Cortex-M7微控制器&#xff0c;支持多种图像处理功能&#xff0c;如颜色识别、形状检测等。而STM32是STMicroelectronics公司推出的基于ARM Cortex内核的…...

C#基于SkiaSharp实现印章管理(11)

PdfSharpCore支持类似GDI方式在PDF页面绘制文字、矩形、圆形、多边形、路径、图片等内容&#xff0c;本文学习基于PdfSharpCore将结构化印章数据导出为PDF文件的基本用法&#xff0c;评估其使用可行性。   PdfSharpCore创建PDF文件很方便&#xff0c;调用PdfDocument类创建实…...

Spring使用@Async出现循环依赖原因以及解决方案

场景复现 1、首先项目需要打开spring的异步开关&#xff0c;在application主类上加EnableAsync 2、创建一个包含了Async方法的异步类MessageService&#xff1a; Service public class MessageService {Resource private TaskService taskService; Async public void…...

如何训练 RAG 模型

训练 RAG&#xff08;Retrieval-Augmented Generation&#xff09;模型涉及多个步骤&#xff0c;包括准备数据、构建知识库、配置检索器和生成模型&#xff0c;以及进行训练。以下是一个详细的步骤指南&#xff0c;帮助你训练 RAG 模型。 1. 安装必要的库 确保你已经安装了必…...

鸿蒙网络编程系列34-Wifi热点扫描及连接示例

1. Wifi热点简介 Wifi热点是移动设备接入网络的重要形式&#xff0c;特别是在不具备固定网络接入点的情况下&#xff0c;可以通过Wifi热点灵活方便的接入网络&#xff0c;因此在日常生活中具有广泛的应用。鸿蒙系统也提供了方便的Wifi管理API&#xff0c;支持热点扫描&#xf…...

LVS三种模式工作原理

常用负载均衡设备 实现负载均衡的技术的方式有哪些&#xff1a;硬件层面有F5负载均衡器&#xff0c;网络层层面有LVS(Linux Virtual Server)&#xff0c;应用层层面就是nginx、Haproxy等。 lvs工作在网络层&#xff0c;nginx工作在应用层。 LVS有三种工作模式 lvs是由章文崇…...

【二轮征稿启动】第三届环境工程与可持续能源国际会议持续收录优质稿件

第三届环境工程与与可持续能源国际会议&#xff08;EESE 2024&#xff09;由中南林业科技大学主办&#xff0c;湖南农业大学协办&#xff0c;将于2024年12月20日-22日在湖南长沙召开。 大会邀请到国家杰出青年科学基金获得者、华中科技大学能源与动力工程学院冯光教授&#xf…...

网络安全——防火墙技术

目录 前言基本概念常见防火墙技术防火墙的主要功能防火墙的不足之处相关题目1.组织外部未授权用户访问内部网络2.DMZ区3.包过滤防火墙和代理服务防火墙 前言 这是在软件设计师备考时编写的资料文章&#xff0c;相关内容偏向软件设计师 基本概念 防火墙技术是网络安全领域中的…...

Missing classes detected while running R8报错解决方案

Android 打包release版本时报错如下&#xff1a; > Task :printlib:minifyReleaseWithR8 FAILED AGPBI: {"kind":"error","text":"Missing classes detected while running R8. Please add the missing classes or apply additional ke…...

智能指针

目录 1. 为什么需要智能指针&#xff1f; 2. 内存泄漏 2.1 什么是内存泄漏&#xff0c;内存泄漏的危害 2.2 内存泄漏分类&#xff08;了解&#xff09; 堆内存泄漏(Heap leak) 系统资源泄漏 2.3 如何检测内存泄漏&#xff08;了解&#xff09; 2.4如何避免内存泄漏 3.…...

通过DevTools逃离Chrome沙盒(CVE-2024-6778和CVE-2024-5836)

介绍 这篇博文详细介绍了如何发现CVE-2024-6778和CVE-2024-5836的&#xff0c;这是Chromium web浏览器中的漏洞&#xff0c;允许从浏览器扩展&#xff08;带有一点点用户交互&#xff09;中进行沙盒逃逸。 简而言之&#xff0c;这些漏洞允许恶意的Chrome扩展在你的电脑上运行…...

手持无人机飞手执照,会组装调试入伍当兵有多香!

手持无人机飞手执照&#xff0c;并具备组装调试技能&#xff0c;在入伍当兵时确实会具有显著的优势和吸引力。以下是对这一情况的详细分析&#xff1a; 一、无人机飞手执照的优势 1. 法规遵从与安全保障&#xff1a; 根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关…...

项目经理好累好烦啊,不想干了....

打住&#xff01; 先问问自己&#xff0c;在所有的项目管理过程中&#xff0c;有没有体验到任和何乐趣。如果没有&#xff0c;请不要再继续内耗。 如果有&#xff0c;慎重考虑&#xff0c;然后适当解压&#xff0c;每个岗位都会不同的烦心事&#xff0c;每个企业都不完美&…...

论技术人员“技术人格”的重要意义

此论题从表面上看&#xff0c;是社会科学的&#xff0c;或者心理学的。然其对于信息技术这种科学的工作&#xff0c;又显得非常的重要。作为信息技术的从业者&#xff0c;或者说科学的从业者&#xff0c;具备良好的“技术人格”&#xff0c;对确保工作的质量&#xff0c;与正确…...

Kafka异常重试方案小记

背景 在最近进行的项目架构升级中&#xff0c;我们对原有的核心项目结构进行了细致的拆分。 现在&#xff0c;核心项目与非核心项目之间的通信和数据交换主要通过Kafka这一中间件来实现。 这种设计主要体现在核心项目向非核心项目发送通知&#xff0c;这些通知大致可以分为三个…...

非页面缓冲池占用过高处理方法

1.现象 电脑变莫名其妙得特别卡&#xff0c;明明16G的内存&#xff0c;理论上日常使用&#xff0c;打游戏之类的使用起来完全不会有什么大问题&#xff0c;但是实际使用却是卡的要死。 下面开始查找原因。 2.查找原因 使用win自带的任务管理器&#xff0c;可以看到日常内存…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...