leech可以序列化C++对象到 json、yaml、config等。leech通过编译期反射得到的结构的字段信息,根据该信息对象序列化输出到文档,或者从文档反向序列化到对象。
leech是纯头文件的库,不需要编译。使用leech需要boost.preprocessor和支持C++14的编译器。另外根据文档格式,还需要安装对应的库。
文档格式 | 头文件 | 库 |
---|---|---|
json | leech/json.hpp | nlohmann/json |
yaml | leech/yaml.hpp | YAML-CPP |
config | leech/config.hpp | libconfig |
leech和文档格式之间是解耦合的,只要为某种文档格式包装一个leech需要的接口,leech就可以将对象序列化到该文档中。
leech的反射是为序列化结构数据设计的,因此只支持对数据成员的反射。 现在有一个这样的结构:
struct Base
{
int id;
bool enabled;
};
包含头文件leech/model.hpp后,只需要一行代码可以完成反射:
STRUCT_MODEL(Base, id, enabled)
如果有派生类,可以这样写:
struct MyStruct : public Base
{
int a, b, c;
std::vector<int> d;
MyNode node;
};
STRUCT_MODEL_INHERIT(MyStruct, (Base), a, b, c, d, node)
因为leech的反射是定义在结构之外的,要保证leech能访问到结构内部成员。如果有必要,需要申明为友元:
STRUCT_MODEL_FRIEND(MyStruct)
如果字段可以不出现在文档中,需要标明该字段是可选的:
STRUCT_MODEL_SET_OPTIONAL(MyStruct, a)
做好反射后,leech提供put和get操作完成对对象的序列化:
namespace leech
{
template<typename Document, typename T>
Document& put(Document&& doc, const T& v);
template<typename Document, typename T>
Document& put(Document& doc, typename Document::element_type& element, const T& v, const char* name = nullptr);
template<typename Document, typename T>
void get(const Document& doc, T& v);
template<typename Document, typename T>
void get(const Document& doc, const typename Document::element_type& element, T& v, const char* name = nullptr);
}
用法很简单:
MyStruct s{ };
leech::json::document ar=leech::json::load_file("test.json");
leech::get(ar, ar["aaa"], s);
template<typename S, typename Pred>
bool find_field(const char* name, Pred&& pred);
Pred是一个函数,当找到指定的字段时,会被调用。它的参数是对应的字段信息。
template<typename S, typename M>
void Pred(struct_field<S, M>& field_info);
字段信息的定义类似:
template<typename S, typename M>
struct struct_field
{
public:
typedef M value_type;
const char* name() const noexcept;
value_type& value(S& v) const noexcept;
const value_type& value(const S& v) const noexcept; bool optional() const noexcept;
void optional(bool v) noexcept;
template<typename Document>
void put(Document& doc, typename Document::element_type& element, const T& v) const;
template<typename Document>
void get(const Document& doc, const typename Document::element_type& element, S& v) const;
template<typename Pred>
void visit(S& v, Pred&& pred) const;
};
template<typename S, typename T>
bool assign(S& s, const char* name, const T& v);
template<typename S, typename T>
bool assign(S& s, size_t index, const T& v);
template<typename S>
constexpr void field_count();
template<typename S, typename Pred>
void for_each(S& s, Pred&& pred);
template<typename S, typename Pred>
void for_each(const S& s, Pred&& pred);