You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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 ==========

问题分析与修复

核心问题点

  1. 基类sf::Shape序列化缺失:日志明确报错std::shared_ptr<sf::Shape>找不到序列化函数——你只实现了子类的序列化,但Cereal处理多态类型(基类指针/智能指针指向子类)时,必须有基类的序列化支持,还要注册子类与基类的关系。
  2. sf::Color序列化缺失:代码直接序列化sf::Color对象,但未给该类型编写序列化逻辑,Cereal无法识别。
  3. 序列化逻辑的读写不分:当前代码在序列化时同时执行了读属性和写回对象的操作,不管是归档(保存)还是加载都会执行setXXX,这不符合Cereal的逻辑——归档时不需要修改对象,只有加载时才需要。
  4. 显式实例化签名不匹配: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:24:59