使用Cereal序列化SFML图形触发static_assert错误求助
问题:Cereal序列化SFML图形触发static_assert错误
我正在开发一款类似MS Paint的2D绘图程序,尝试用Cereal库序列化SFML图形,但构建时触发了static_assert错误。网上查到的相关问题大多是因为未给函数标记模板类,以下是我代码中唯一使用该库的部分及构建日志,求帮忙排查问题!
代码实现
#pragma once #include <SFML/Graphics.hpp> #include <cereal/cereal.hpp> namespace cereal { template <class Archive> void serialize(Archive& ar, sf::Vector2f& vector) { ar(CEREAL_NVP(vector.x), CEREAL_NVP(vector.y)); } template <class Archive> void serialize(Archive& ar, sf::RectangleShape& shape) { sf::Vector2f position = shape.getPosition(); sf::Vector2f size = shape.getSize(); sf::Color fillColor = shape.getFillColor(); sf::Color outlineColor = shape.getOutlineColor(); float outlineThickness = shape.getOutlineThickness(); ar(CEREAL_NVP(position), CEREAL_NVP(size), CEREAL_NVP(fillColor), CEREAL_NVP(outlineColor), CEREAL_NVP(outlineThickness)); shape.setPosition(position); shape.setSize(size); shape.setFillColor(fillColor); shape.setOutlineColor(outlineColor); shape.setOutlineThickness(outlineThickness); } template <class Archive> void serialize(Archive& ar, sf::CircleShape& circle) { std::size_t pointCount = circle.getPointCount(); sf::Vector2f position = circle.getPosition(); float radius = circle.getRadius(); sf::Color fillColor = circle.getFillColor(); sf::Color outlineColor = circle.getOutlineColor(); float outlineThickness = circle.getOutlineThickness(); ar(CEREAL_NVP(position), CEREAL_NVP(radius), CEREAL_NVP(fillColor), CEREAL_NVP(outlineColor), CEREAL_NVP(outlineThickness)); circle.setPointCount(pointCount); circle.setPosition(position); circle.setRadius(radius); circle.setFillColor(fillColor); circle.setOutlineColor(outlineColor); circle.setOutlineThickness(outlineThickness); } } template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::Vector2f&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::RectangleShape&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::CircleShape&);
构建日志
Build started at 7:21 PM... 1>------ Build started: Project: Simple2D-DrawingApplication, Configuration: Debug Win32 ------ 1>DrawingDataSaver.cpp 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(51,112): warning C4667: 'void cereal::serialize(cereal::BinaryOutputArchive &,sf::RectangleShape &)': no function template defined that matches forced instantiation 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(52,109): warning C4667: 'void cereal::serialize(cereal::BinaryOutputArchive &,sf::CircleShape &)': no function template defined that matches forced instantiation 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\cereal-1.3.2\include\cereal\cereal.hpp(570,87): error C2338: static_assert failed: 'cereal could not find any output serialization functions for the provided type and archive combination. 1> Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). 1> Serialize functions generally have the following signature: 1> template<class Archive> 1> void serialize(Archive & ar) 1> { 1> ar( member1, member2, member3 ); 1> } 1> ' 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\cereal-1.3.2\include\cereal\cereal.hpp(444,13): message : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::processImpl<std::shared_ptr<sf::Shape>,(cereal::traits::detail::sfinae)0>(const T &)' being compiled 1> with 1> [ 1> ArchiveType=cereal::BinaryOutputArchive, 1> T=std::shared_ptr<sf::Shape> 1> ] 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\cereal-1.3.2\include\cereal\cereal.hpp(333,13): message : see reference to function template instantiation 'void cereal::OutputArchive<cereal::BinaryOutputArchive,1>::process<const std::shared_ptr<sf::Shape>&>(T)' being compiled 1> with 1> [ 1> T=const std::shared_ptr<sf::Shape> & 1> ] 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\DrawingDataSaver.cpp(19,3): message : see reference to function template instantiation 'ArchiveType &cereal::OutputArchive<ArchiveType,1>::operator ()<const std::shared_ptr<sf::Shape>&>(const std::shared_ptr<sf::Shape> &)' being compiled 1> with 1> [ 1> ArchiveType=cereal::BinaryOutputArchive 1> ] 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\DrawingDataSaver.cpp(19,10): message : see the first reference to 'cereal::OutputArchive<cereal::BinaryOutputArchive,1>::operator ()' in 'DrawingDataSaver::Save' 1>DrawingApp.cpp 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(51,112): warning C4667: 'void cereal::serialize(cereal::BinaryOutputArchive &,sf::RectangleShape &)': no function template defined that matches forced instantiation 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(52,109): warning C4667: 'void cereal::serialize(cereal::BinaryOutputArchive &,sf::CircleShape &)': no function template defined that matches forced instantiation 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(10,3): error C2064: term does not evaluate to a function taking 2 arguments 1>D:\Dev\LocalRepos\Simple2D-DrawingApplication\Src\SFMLSerialization.h(50,23): message : see reference to function template instantiation 'void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive &,sf::Vector2f &)' being compiled 1>Generating Code... 1>Done building project "Simple2D-DrawingApplication.vcxproj" -- FAILED. ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== ========== Build completed at 7:21 PM and took 05.360 seconds ==========
问题分析与修复
核心问题点
- 基类
sf::Shape序列化缺失:日志明确报错std::shared_ptr<sf::Shape>找不到序列化函数——你只实现了子类的序列化,但Cereal处理多态类型(基类指针/智能指针指向子类)时,必须有基类的序列化支持,还要注册子类与基类的关系。 sf::Color序列化缺失:代码直接序列化sf::Color对象,但未给该类型编写序列化逻辑,Cereal无法识别。- 序列化逻辑的读写不分:当前代码在序列化时同时执行了读属性和写回对象的操作,不管是归档(保存)还是加载都会执行
setXXX,这不符合Cereal的逻辑——归档时不需要修改对象,只有加载时才需要。 - 显式实例化签名不匹配:C4667警告是因为显式实例化的函数签名和模板函数的定义不匹配。
修复后的代码
#pragma once #include <SFML/Graphics.hpp> #include <cereal/cereal.hpp> #include <cereal/types/polymorphic.hpp> #include <cereal/types/shared_ptr.hpp> namespace cereal { // 序列化sf::Vector2f template <class Archive> void serialize(Archive& ar, sf::Vector2f& vector) { ar(CEREAL_NVP(vector.x), CEREAL_NVP(vector.y)); } // 序列化sf::Color template <class Archive> void serialize(Archive& ar, sf::Color& color) { ar(CEREAL_NVP(color.r), CEREAL_NVP(color.g), CEREAL_NVP(color.b), CEREAL_NVP(color.a)); } // 基类sf::Shape的序列化(多态支持) template <class Archive> void serialize(Archive& ar, sf::Shape& shape) { sf::Vector2f position = shape.getPosition(); sf::Color fillColor = shape.getFillColor(); sf::Color outlineColor = shape.getOutlineColor(); float outlineThickness = shape.getOutlineThickness(); ar(CEREAL_NVP(position), CEREAL_NVP(fillColor), CEREAL_NVP(outlineColor), CEREAL_NVP(outlineThickness)); // 仅在加载归档时回写属性 if constexpr(Archive::is_loading::value) { shape.setPosition(position); shape.setFillColor(fillColor); shape.setOutlineColor(outlineColor); shape.setOutlineThickness(outlineThickness); } } // 子类sf::RectangleShape的序列化 template <class Archive> void serialize(Archive& ar, sf::RectangleShape& shape) { // 先序列化基类部分 ar(cereal::base_class<sf::Shape>(&shape)); sf::Vector2f size = shape.getSize(); ar(CEREAL_NVP(size)); if constexpr(Archive::is_loading::value) { shape.setSize(size); } } // 子类sf::CircleShape的序列化 template <class Archive> void serialize(Archive& ar, sf::CircleShape& circle) { // 先序列化基类部分 ar(cereal::base_class<sf::Shape>(&circle)); std::size_t pointCount = circle.getPointCount(); float radius = circle.getRadius(); ar(CEREAL_NVP(pointCount), CEREAL_NVP(radius)); if constexpr(Archive::is_loading::value) { circle.setPointCount(pointCount); circle.setRadius(radius); } } } // 注册多态类型,让Cereal识别基类指针指向的子类对象 CEREAL_REGISTER_TYPE(sf::RectangleShape) CEREAL_REGISTER_TYPE(sf::CircleShape) CEREAL_REGISTER_POLYMORPHIC_RELATION(sf::Shape, sf::RectangleShape) CEREAL_REGISTER_POLYMORPHIC_RELATION(sf::Shape, sf::CircleShape) // 显式实例化输出归档支持 template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::Vector2f&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::Color&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::Shape&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::RectangleShape&); template void cereal::serialize<cereal::BinaryOutputArchive>(cereal::BinaryOutputArchive&, sf::CircleShape&); // 显式实例化输入归档支持 template void cereal::serialize<cereal::BinaryInputArchive>(cereal::BinaryInputArchive&, sf::Vector2f&); template void cereal::serialize<cereal::BinaryInputArchive>(cereal::BinaryInputArchive&, sf::Color&); template void cereal::serialize<cereal::BinaryInputArchive>(cereal::BinaryInputArchive&, sf::Shape&); template void cereal::serialize<cereal::BinaryInputArchive>(cereal::BinaryInputArchive&, sf::RectangleShape&); template void cereal::serialize<cereal::BinaryInputArchive>(cereal::BinaryInputArchive&, sf::CircleShape&);
关键修改说明
- 新增
sf::Color的序列化函数,处理颜色的RGBA四个分量。 - 给
sf::Shape基类添加序列化逻辑,在子类中用base_class复用基类序列化逻辑,实现多态支持。 - 使用
if constexpr(Archive::is_loading::value)区分归档和加载操作:归档时只读取属性保存,加载时才将属性写回对象。 - 添加多态类型注册宏,让Cereal能够正确识别基类指针指向的子类实例。
- 修正显式实例化的签名,确保与模板函数定义完全匹配,同时补充了输入归档的实例化支持。
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

