如何使用cereal库序列化vulkan.hpp中Flags模板封装的枚举类型?
解决cereal序列化Vulkan vk::Flags类的问题
问题原因拆解
- 直接序列化
tag触发无限递归:自定义的serialize函数传入Flags类型参数给archive,cereal重载决议时会优先匹配该函数,导致循环自调用最终栈溢出。 - 强转
BitType反序列化失效:一是如果Flags包含多个位标记,强转为单个枚举值属于未定义行为;二是反序列化时(BitType)tag是临时右值,读取到的数值只会赋值给临时对象,不会修改原tag的内容,因此反序列化后值始终为0。 - 修改私有成员
m_mask的方案侵入性太强,不符合第三方库使用规范。
可行解决方案
利用vk::Flags公开的原生接口实现序列化,不需要修改任何vulkan.hpp代码:
将序列化逻辑拆分为独立的save/load函数,放到和vk::Flags同命名空间下保证ADL(参数依赖查找)生效:
#include <vulkan/vulkan.hpp> #include <cereal/cereal.hpp> namespace vk { template <class Archive, typename BitType> void save(Archive& archive, Flags<BitType> const& tag) { // 调用公开的显式转换接口获取底层掩码值 using MaskType = typename Flags<BitType>::MaskType; archive(static_cast<MaskType>(tag)); } template <class Archive, typename BitType> void load(Archive& archive, Flags<BitType>& tag) { // 读取底层掩码后用公开构造函数生成合法Flags对象赋值 using MaskType = typename Flags<BitType>::MaskType; MaskType mask; archive(mask); tag = Flags<BitType>(mask); } }
该方案完全依赖vk::Flags的公开接口:显式转换为底层MaskType的运算符、接受MaskType参数的构造函数、默认赋值运算符,所有操作都符合类型安全要求,序列化和反序列化结果完全正确。
内容的提问来源于stack exchange,提问作者Makogan
相关产品推荐
相关产品推荐

