c++的运行时反射库,允许对自定义类型进行序列化和反序列化



我正在寻找一个库,它允许在几行代码中序列化和反序列化自定义类型。

我已经测试了这个库RTTR,但不幸的是,它不符合我的目的(文档也很差(。

我希望在伪代码中实现的是:

void serializeInstance(instance)
{
for (property in instance)
{
serializeProperty("propertyName", property);
}
}
void deserializeInstance()
{
// Getting the type of the component from a string stored in a file
type = getType(component["Type"]); 
decltype(type) component;

properties = getProperties(component["Properties"]);
for (propertyName in properties)
{
// need to cast this to the right type
component.property = getPropertyValue(propertyName["Value"]);
}
}

为了简单起见,我正在尝试做一些类似于Unity对组件序列化所做的事情。

这是我的组件的类图:ClassDiagram我希望能够从Yaml文件中反序列化我的所有组件。

YAML文件:

Scene Object: 1252896902983049
Component: Mesh
Vertices: {...}
Indices: {...}
Path: ./Assets/Mesh/Cube.obj

.cpp文件:

YAML::Emitter node;
// Storing Component Name in a string (in this case "Mesh")
std::string componentName = node["Scene Object"]["Component"].as<std::string>();

// Don't know how to do this so I'll paste some pseudo code
// This auto should return my Mesh component not an instance of IComponent
auto component = generateComponentFromComponentName(componentName);
// Get all the attributes in class component by name
foreach (attribute in component.getAttributes())
// The cast to the attribute type is already implemented by me
attribute = node["Scene Object"]["Component"][attribute.name()].as<attribute.type()>();

Oops库正在执行您想要的操作。它是为使用反射进行序列化而编写的。

https://bitbucket.org/barczpe/oops

您可以在wiki页面上找到示例和一些文档。

我实现了类图中的类,并将类型描述或反射添加到所有类中。它为您处理yaml文件。您的代码不需要处理yaml树,也不需要将yaml节点与类的成员连接起来。这一切都是由Oops完成的。这更快更简单。Oops有自己的yaml解析器,它不从yaml文件构建即时数据结构。但是,我不建议使用yaml文件格式。它不是序列化C++对象的最佳方法。如果可以选择,请使用Oops库的文本格式。它是类似的,但设计用于存储C++对象。

以下是代码(您也可以在Oops单元测试的AbstractClasses_test.cpp文件中找到(:

#include "SerializationTest.h"
#include <oops/Enum2StringTool.h>
#include <oops/rPropInterface.h>
#include <gtest/gtest.h>
#include <string>

using namespace rOops;
class IComponent
{
public:
virtual ~IComponent() = default;
IComponent() = default;
virtual void init(short) = 0;
rOOPS_ADD_PROPERTY_INTERFACE_ABSTRACT(IComponent)
{
}
};
DECLARE_ENUM_CLASS(CameraType, std::uint8_t,
eNone = 0,
eType1,
eType2
);
rOOPS_DECLARE_ENUM_TYPE_INFO( CameraType, CameraType2String )
class Camera : public IComponent {
public:
Camera() = default;
void init(short p) override
{
height = width = p;
}
private:
CameraType type{CameraType::eNone};
int height{0};
int width{0};
rOOPS_ADD_PROPERTY_INTERFACE(Camera)
{
rOOPS_INHERIT(IComponent);
rOOPS_PROPERTY(type);
rOOPS_PROPERTY(height);
rOOPS_PROPERTY(width);
}
};
rOOPS_DECLARE_STL_LIST_TYPE_INFO(std::vector<long>)
class Mesh : public IComponent
{
public:
Mesh() = default;
void init(short p) override
{
indices.push_back(p);
path = std::to_string(p);
}
private:
std::vector<long> indices;
std::string path;
rOOPS_ADD_PROPERTY_INTERFACE(Mesh)
{
rOOPS_INHERIT(IComponent);
rOOPS_PROPERTY(indices);
rOOPS_PROPERTY(path);
}
};
class ILight : public IComponent
{
public:
~ILight() override = default;
ILight() = default;
rOOPS_ADD_PROPERTY_INTERFACE_ABSTRACT(ILight)
{
rOOPS_INHERIT(IComponent);
}
};
using Vec3 = std::array<double, 3>;
rOOPS_DECLARE_STL_ARRAY_TYPE_INFO(Vec3)
class PointLight : public ILight
{
public:
PointLight() = default;
void init(short p) override
{
AO[0] = Diffuse[1] = Specular[2] = p;
}
private:
Vec3 AO{};
Vec3 Diffuse{};
Vec3 Specular{};
rOOPS_ADD_PROPERTY_INTERFACE(PointLight)
{
rOOPS_INHERIT(ILight);
rOOPS_PROPERTY(AO);
rOOPS_PROPERTY(Diffuse);
rOOPS_PROPERTY(Specular);
}
};
rOOPS_DECLARE_STL_LIST_TYPE_INFO(std::vector<std::unique_ptr<IComponent>>)
TEST(AbstractClassesTest, IComponents)
{
std::vector<std::unique_ptr<IComponent>> v;
v.push_back(std::make_unique<Camera>()); v.back()->init(1);
v.push_back(std::make_unique<Mesh>()); v.back()->init(2);
v.push_back(std::make_unique<PointLight>()); v.back()->init(3);
std::stringstream strm(cStringStreamMode);
rOopsYamlFormat format(strm);
save(format, v, "Components");
std::cout << "========== save ==========" << std::endl;
std::cout << strm.str() << std::endl;
std::cout << "==========================" << std::endl;
rOopsYamlParser parser(strm, "Components");
std::vector<std::unique_ptr<IComponent>> v2;
load(parser, v2);
}

这是yaml文件:

Components: !std::vector<std::unique_ptr<IComponent>>
- !Camera&94841900126576
IComponent:
type: eNone
height: 1
width: 1
- !Mesh&94841900120480
IComponent:
indices:
- 2
path: "2"
- !PointLight&94841900126768
ILight:
IComponent:
AO:
- 3
- 0
- 0
Diffuse:
- 0
- 3
- 0
Specular:
- 0
- 0
- 3

最新更新