cereal代码阅读有感
1. 优雅地实现单例模板,见::cereal::detail::StaticObject; 对比apollo的单例:https://zhuanlan.zhihu.com/p/391151328
2. 静态初始化,见CEREAL_CLASS_VERSION;
3. 静态类对象避免重定义,见::cereal::detail::<匿名>::version_binding_tag;
4. RTTI 运行时获取基类包含的子类类型信息:CEREAL_REGISTER_TYPE、CEREAL_REGISTER_POLYMORPHIC_RELATION
其中,当我们把某个子类指针转为基类指针后,再对其做序列化,cereal能识别出运行时类型和构造时类型不一致,并报错。
CEREAL_REGISTER_TYPE:以子类的类型为key,注册了shared_ptr\unic_ptr的save/load 函数到 OutputBindingMap/InputBindingMap(两个单例map)中,在save/load函数中通过模板匹配调用到 对应的cast函数,cast成子类后便可序列化;以shared_ptr的save函数为例,代码如下。cast函数的实现,与下面的CEREAL_REGISTER_POLYMORPHIC_RELATION息息相关。
serializers.shared_ptr = [&](void * arptr, void const * dptr, std::type_info const & baseInfo) { Archive & ar = *static_cast<Archive*>(arptr); writeMetadata(ar); auto ptr = PolymorphicCasters::template downcast<T>( dptr, baseInfo ); savePolymorphicSharedPtr( ar, ptr, typename ::cereal::traits::has_shared_from_this<T>::type() ); };
CEREAL_REGISTER_POLYMORPHIC_RELATION:以父类的类型为key,注册了子类map,其中子类map以子类类型为key,value为vector<PolymorphicCaster*>(存了downcast/upcast函数)
//! Maps from a derived type index to a set of chainable casters using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>; //! Maps from base type index to a map from derived type index to caster std::unordered_map<std::type_index, DerivedCasterMap> map;
//! Saving std::shared_ptr for polymorphic types, abstract template <class Archive, class T> inline typename std::enable_if<std::is_polymorphic<T>::value && std::is_abstract<T>::value, void>::type CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr ) { std::type_info const & ptrinfo = typeid(*ptr.get()); static std::type_info const & tinfo = typeid(T); auto const & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map; auto binding = bindingMap.find(std::type_index(ptrinfo)); if(binding == bindingMap.end()) UNREGISTERED_POLYMORPHIC_EXCEPTION(save, cereal::util::demangle(ptrinfo.name())) binding->second.shared_ptr(&ar, ptr.get(), tinfo); }
疑问:1. polymorphic_serialization_support<Archive,T>::instantiate(),register type时,这个函数是如何触发的?
2. 为啥DerivedCasterMap的value类型需要为vector?
5. 使用标签分发实现函数偏特化:编译期条件判断,作为函数入参来实现函数多态:cereal::detail::create_bings::load/save
6. 通过继承来间接访问protect成员,参考:cereal::stack_detail::container
通过“C++标准:在C++ 模版显式实例化的时候,可以访问类的私有成员”来访问private成员,参考:http://purecpp.cn/detail?id=2372
template <typename T, auto... field> struct ThiefMember { friend auto steal_impl(T& t) { return std::make_tuple(field...); } }; class Bank_t{ int id; std::string name; int foo(){ return 42; } public: Bank_t(int i, std::string str) : id(i), name(str){} }; auto steal_impl(Bank_t& t); template struct ThiefMember<Bank_t, &Bank_t::id, &Bank_t::name, &Bank_t::foo>; int main(void) { Bank_t bank(1, "ok"); auto tp = steal_impl(bank); auto id = bank.*(std::get<0>(tp)); // 1 auto name = bank.*(std::get<1>(tp)); //ok auto r = (bank.*(std::get<2>(tp)))(); // 42 }
REFS:https://zhuanlan.zhihu.com/p/268600376