网站管理系统安装,wordpress备案选项,住建官网查询,ps做网站首页怎么运用起来iguana
Github : https://github.com/fananchong/iguana
官方介绍#xff1a; universal serialization engine
虽然官方介绍是通用的序列化引擎#xff0c;但实际上目前只支持#xff1a;
jsonyamlxml
不过#xff0c; C 结构体/类的反射部分是通用的
通过该库…iguana
Github : https://github.com/fananchong/iguana
官方介绍 universal serialization engine
虽然官方介绍是通用的序列化引擎但实际上目前只支持
jsonyamlxml
不过 C 结构体/类的反射部分是通用的
通过该库可以学习到使用宏和模板实现 C 反射的一种方法
iguana 用法示例
先简单看下 iguana 如何实现
以下代码摘自 https://github.com/qicosmos/iguana?tabreadme-ov-file#tutorial
定义 person
struct person
{std::string name;int age;
};
REFLECTION(person, name, age) //define meta data序列化为 json 字符串
person p { tom, 28 };
iguana::string_stream ss; // here use std::string is also ok
iguana::to_json(p, ss);
std::cout ss.str() std::endl; 从 json 字符串反序列化回 person
std::string json { \name\ : \tom\, \age\ : 28};
person p;
iguana::from_json(p, json);以上例子中通过REFLECTION(person, name, age)在编译期反射 person 相关字段信息
运行态可以利用这些反射的信息做to_json和from_json
REFLECTION 宏分析
REFLECTION 宏定义如下
#define REFLECTION(STRUCT_NAME, ...) \MAKE_META_DATA(STRUCT_NAME, #STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), \__VA_ARGS__)#define MAKE_META_DATA(STRUCT_NAME, TABLE_NAME, N, ...) \static constexpr inline std::arrayfrozen::string, N arr_##STRUCT_NAME { \MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__))}; \static constexpr inline std::string_view fields_##STRUCT_NAME { \MAKE_NAMES(__VA_ARGS__)}; \static constexpr inline std::string_view name_##STRUCT_NAME TABLE_NAME; \MAKE_META_DATA_IMPL(STRUCT_NAME, \MAKE_ARG_LIST(N, STRUCT_NAME::FIELD, __VA_ARGS__))#define MAKE_META_DATA_IMPL(STRUCT_NAME, ...) \[[maybe_unused]] inline static auto iguana_reflect_members( \STRUCT_NAME const ) { \struct reflect_members { \constexpr decltype(auto) static apply_impl() { \return std::make_tuple(__VA_ARGS__); \} \using size_type \std::integral_constantsize_t, GET_ARG_COUNT(__VA_ARGS__); \constexpr static std::string_view name() { return name_##STRUCT_NAME; } \constexpr static std::string_view struct_name() { \return std::string_view(#STRUCT_NAME, sizeof(#STRUCT_NAME) - 1); \} \constexpr static std::string_view fields() { \return fields_##STRUCT_NAME; \} \constexpr static size_t value() { return size_type::value; } \constexpr static std::arrayfrozen::string, size_type::value arr() { \return arr_##STRUCT_NAME; \} \}; \return reflect_members{}; \}把REFLECTION(person, name, age)展开
static constexpr inline std::arrayfrozen::string, 2 arr_person {std::string_view(name, sizeof(name) - 1),std::string_view(age, sizeof(age) - 1),
};
static constexpr inline std::string_view fields_person {name, age,
};
static constexpr inline std::string_view name_person person;
[[maybe_unused]] inline static auto iguana_reflect_members(person const ) {struct reflect_members {constexpr decltype(auto) static apply_impl() {return std::make_tuple(person::name, person::age);}using size_type std::integral_constantsize_t, 2;constexpr static std::string_view name() { return name_person; }constexpr static std::string_view struct_name() {return std::string_view(person, sizeof(person) - 1);}constexpr static std::string_view fields() { return fields_person; }constexpr static size_t value() { return size_type::value; }constexpr static std::arrayfrozen::string, size_type::value arr() {return arr_person;}};return reflect_members{};
}从宏展开代码可以看到 REFLECTION 定义可以得到 person 的以下元信息
元信息的宏定义person说明arr_##STRUCT_NAMEarr_person字段名列表类型为 std::arrayfrozen::string, 2fields_##STRUCT_NAMEfields_person字段名列表类型为 std::string_viewname_##STRUCT_NAMEname_person结构体/类名iguana_reflect_members(STRUCT_NAME const ){}iguana_reflect_members(person const )元数据信息。通过调用 iguana_reflect_members 返回 reflect_members 结构体
reflect_members 元数据结构体除了上面表格中列的内容还提供了
方法元数据说明apply_impl()字段地址列表类型 std::tuple实现反射的关键。通过它结合结构体/类实例获取结构体/类实例字段的值或赋值value()字段个数
from_json 实现
from_json 函数实现在iguana/json_reader.hpp 504 行 - 599 行
把一些边界代码、遍历代码去掉核心逻辑如下 std::string_view key detail::get_key(it, end);static constexpr auto frozen_map get_iguana_struct_mapT();const auto member_it frozen_map.find(key);std::visit([](auto member_ptr) IGUANA__INLINE_LAMBDA {from_json_impl(value.*member_ptr, it, end);},member_it-second);这段代码的意思是
代码说明it, endit 指向当前解析到 json 字符串的位置 end json 串结尾位置key detail::get_key(it, end)获取字段名frozen_map get_iguana_struct_mapT()获取一个 map 该 map key 为字段名值为 std::variant 类型的字段地址 上面提到 apply_impl() 返回字段地址列表类型 std::tuple get_iguana_struct_map 函数就是把 std::tuple 类型的内容编译期转成 std::variant 类型std::visit对 std::variant 类型对象做访问from_json_impl(value.*member_ptr, it, end)from_json_impl 是个模板不同类型都有特化实现 it, end 获得 value 值转化为对应类型赋值 value.*member_ptr
from_json 过程思路很清晰就是把 key - value (字段字段值)填充到对象上
从 apply_impl() 得到的字段地址列表实际上已经可以实现这个思路
iguana 在实现上考虑到编码的简洁引入了 std::visit - std::variant 编程技巧
对每种类型的解析赋值过程均对应一个 from_json_impl 类型特化的模板函数
这样就不会有 if else 颓长的类型判断代码
同时成员字段也可能是需要反射的类型那么 from_json_impl 类型特化的模板函数也实现一个就可以实现递归解析了
template typename U, typename It, std::enable_if_trefletable_vU, int 0
IGUANA_INLINE void from_json_impl(U value, It it, It end) {from_json(value, it, end);
}再举例解析 bool 类型值如下 template typename U, typename It, std::enable_if_tbool_vU, int 0
IGUANA_INLINE void from_json_impl(U value, It it, It end) {skip_ws(it, end);if (it end)IGUANA_LIKELY {switch (*it) {case t:it;matchr, u, e(it, end);value true;break;case f:it;matcha, l, s, e(it, end);value false;break;IGUANA_UNLIKELY default: throw std::runtime_error(Expected true or false);}}elseIGUANA_UNLIKELY { throw std::runtime_error(Expected true or false); }
}to_json 函数实现思路类似不再复述
总结
iguana 实现反射思考
通过定义 REFLECTION 宏在编译期生成结构体/类的元数据信息 字段名列表字段地址列表将字段地址列表做成 std::tuple将该 std::tuple 做成 std::map , 其 key 为字段名其值为 std::variant 类型字段地址 不同格式的序列化、反序列最终要通过字段名给对象的字段赋值或取值 通过 std::visit - std::variant 编程技巧使用函数类型特化方式避免 if else 这种类型分支判断
以上