通用序列化和反序列化实现思路
本文简单的记录一下采用模板来实现序列化与反序列的思路, 同时采用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;
}
相关文章:
通用序列化和反序列化实现思路
本文简单的记录一下采用模板来实现序列化与反序列的思路, 同时采用C20标准的concept和requires来简化模板函数的选择。 首先了解一下自定义类支持序列化的两种方式: 一、序列化自定义类型(侵入式) 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组复制实践 (强一致性主从同步) 2、数据库高可用MHA应用介绍 3、数据库高可用MHA环境…...

js监听div尺寸,ResizeObserver
示例: <!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是一种开源的微型机器视觉模块,基于ARM Cortex-M7微控制器,支持多种图像处理功能,如颜色识别、形状检测等。而STM32是STMicroelectronics公司推出的基于ARM Cortex内核的…...

C#基于SkiaSharp实现印章管理(11)
PdfSharpCore支持类似GDI方式在PDF页面绘制文字、矩形、圆形、多边形、路径、图片等内容,本文学习基于PdfSharpCore将结构化印章数据导出为PDF文件的基本用法,评估其使用可行性。 PdfSharpCore创建PDF文件很方便,调用PdfDocument类创建实…...
Spring使用@Async出现循环依赖原因以及解决方案
场景复现 1、首先项目需要打开spring的异步开关,在application主类上加EnableAsync 2、创建一个包含了Async方法的异步类MessageService: Service public class MessageService {Resource private TaskService taskService; Async public void…...
如何训练 RAG 模型
训练 RAG(Retrieval-Augmented Generation)模型涉及多个步骤,包括准备数据、构建知识库、配置检索器和生成模型,以及进行训练。以下是一个详细的步骤指南,帮助你训练 RAG 模型。 1. 安装必要的库 确保你已经安装了必…...

鸿蒙网络编程系列34-Wifi热点扫描及连接示例
1. Wifi热点简介 Wifi热点是移动设备接入网络的重要形式,特别是在不具备固定网络接入点的情况下,可以通过Wifi热点灵活方便的接入网络,因此在日常生活中具有广泛的应用。鸿蒙系统也提供了方便的Wifi管理API,支持热点扫描…...
LVS三种模式工作原理
常用负载均衡设备 实现负载均衡的技术的方式有哪些:硬件层面有F5负载均衡器,网络层层面有LVS(Linux Virtual Server),应用层层面就是nginx、Haproxy等。 lvs工作在网络层,nginx工作在应用层。 LVS有三种工作模式 lvs是由章文崇…...

【二轮征稿启动】第三届环境工程与可持续能源国际会议持续收录优质稿件
第三届环境工程与与可持续能源国际会议(EESE 2024)由中南林业科技大学主办,湖南农业大学协办,将于2024年12月20日-22日在湖南长沙召开。 大会邀请到国家杰出青年科学基金获得者、华中科技大学能源与动力工程学院冯光教授…...
网络安全——防火墙技术
目录 前言基本概念常见防火墙技术防火墙的主要功能防火墙的不足之处相关题目1.组织外部未授权用户访问内部网络2.DMZ区3.包过滤防火墙和代理服务防火墙 前言 这是在软件设计师备考时编写的资料文章,相关内容偏向软件设计师 基本概念 防火墙技术是网络安全领域中的…...

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

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

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

手持无人机飞手执照,会组装调试入伍当兵有多香!
手持无人机飞手执照,并具备组装调试技能,在入伍当兵时确实会具有显著的优势和吸引力。以下是对这一情况的详细分析: 一、无人机飞手执照的优势 1. 法规遵从与安全保障: 根据《民用无人驾驶航空器系统驾驶员管理暂行规定》等相关…...
项目经理好累好烦啊,不想干了....
打住! 先问问自己,在所有的项目管理过程中,有没有体验到任和何乐趣。如果没有,请不要再继续内耗。 如果有,慎重考虑,然后适当解压,每个岗位都会不同的烦心事,每个企业都不完美&…...
论技术人员“技术人格”的重要意义
此论题从表面上看,是社会科学的,或者心理学的。然其对于信息技术这种科学的工作,又显得非常的重要。作为信息技术的从业者,或者说科学的从业者,具备良好的“技术人格”,对确保工作的质量,与正确…...

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

非页面缓冲池占用过高处理方法
1.现象 电脑变莫名其妙得特别卡,明明16G的内存,理论上日常使用,打游戏之类的使用起来完全不会有什么大问题,但是实际使用却是卡的要死。 下面开始查找原因。 2.查找原因 使用win自带的任务管理器,可以看到日常内存…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
云原生周刊:k0s 成为 CNCF 沙箱项目
开源项目推荐 HAMi HAMi(原名 k8s‑vGPU‑scheduler)是一款 CNCF Sandbox 级别的开源 K8s 中间件,通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度,为容器提供统一接口,实现细粒度资源配额…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式
pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图,如果边框加在dom上面,pdf-lib导出svg的时候并不会导出边框,所以只能在echarts图上面加边框 grid的边框是在图里…...

基于小程序老人监护管理系统源码数据库文档
摘 要 近年来,随着我国人口老龄化问题日益严重,独居和居住养老机构的的老年人数量越来越多。而随着老年人数量的逐步增长,随之而来的是日益突出的老年人问题,尤其是老年人的健康问题,尤其是老年人产生健康问题后&…...
el-amap-bezier-curve运用及线弧度设置
文章目录 简介示例线弧度属性主要弧度相关属性其他相关样式属性完整示例链接简介 el-amap-bezier-curve 是 Vue-Amap 组件库中的一个组件,用于在 高德地图 上绘制贝塞尔曲线。 基本用法属性path定义曲线的路径,可以是多个弧线段的组合。stroke-weight线条的宽度。stroke…...

JUC并发编程(二)Monitor/自旋/轻量级/锁膨胀/wait/notify/锁消除
目录 一 基础 1 概念 2 卖票问题 3 转账问题 二 锁机制与优化策略 0 Monitor 1 轻量级锁 2 锁膨胀 3 自旋 4 偏向锁 5 锁消除 6 wait /notify 7 sleep与wait的对比 8 join原理 一 基础 1 概念 临界区 一段代码块内如果存在对共享资源的多线程读写操作…...