博客地址:http://home.cnblogs.com/u/zengjianrong/

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;
  序列化/反序列化时,通过typeid(*ptr.get())得到子类类型信息,通过typeid(T)得到父类类型信息,先从OutputBindingMap/InputBindingMap找到序列化函数,完成序列化。代码如下,部分无关代码被删减了。
  //! 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

posted @ 2023-06-08 10:52  black_man  阅读(107)  评论(0编辑  收藏  举报