【问题标题】:boost serialisation of forwrd declared classes促进前向声明类的序列化
【发布时间】:2018-06-05 12:35:45
【问题描述】:

我想序列化具有彼此的 std::shared_ptr 作为成员并且在不同文件中声明和定义的类。我的代码的一个最小示例是:

    //auxiliary.h
#include <memory>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>



class A;
class B;
typedef std::shared_ptr< A > A_ptr;
typedef std::shared_ptr< B > B_ptr;


//A.h
#include "auxiliary.h"

class A{
  B_ptr bpt;
  void foo();
  //...
};


//A.cpp
#include "A.h"
void A::foo()
{
    //implementation
}


//B.h
#include "auxiliary.h"

class B{
  A_ptr apt;
  void bar();
  //...   
};


//B.cpp
#include "B.h"
void B::bar()
{
    //implementation
}

当我现在尝试通过编写来序列化这两个类时

//A.h
#include "auxiliary.h"

class A{
  template<class Archive>
  void serialize(Archive & ar, const unsigned int version)
  {
    ar & B_ptr;
  }     
  B_ptr bpt;
  void foo();
  //...
};

//B.h
#include "auxiliary.h"

class B{
  template<class Archive>
  void serialize(Archive & ar, const unsigned int version)
  {
    ar & A_ptr;
  }
  A_ptr apt;
  void bar();
  //...   
};

我收到错误 C2139 "A": undefined class is not allowed as a argument to compiler intrinsic type __is_base_of

我知道编译器宁愿看到在相应的 cpp 文件中定义的序列化函数,但是因为它们是模板,所以不能以通常的方式工作。

我怎么可能修复整个事情?

PS.:我还读到,它有助于在类似的情况下用手册中使用的所有变体和提升状态来实例化模板,这应该通过

某处完成
template void serialize<boost::archive::text_iarchive>(
    boost::archive::text_iarchive & ar, 
    const unsigned int file_version
    );
template void serialize<boost::archive::text_oarchive>(
    boost::archive::text_oarchive & ar, 
    const unsigned int file_version

我尝试了各种方法,但都没有成功。

【问题讨论】:

    标签: templates serialization boost forward-declaration


    【解决方案1】:

    Boost 序列化档案是编译时多态的。这意味着它们结合了定义各个类型和行为的类和函数模板的功能。

    由于 C++ 中模板的性质,这意味着您需要在 POI(实例化点)处对这些模板(及其相关类型)进行完整定义。 (请参阅Why can templates only be implemented in the header file? 了解入门知识)。

    解决方案?

    您可以将序列化实现隐藏在确实包含所有定义的 TU(翻译单元)中。

    或者,您可以使用Polymorphic Archives。在这种情况下,serialize 方法不再严格需要是编译时泛型。

    注意:文档示例将serialize 成员显示为在单个 TU 内显式实例化的模板函数。出于技术原因可能需要这样做¹,尽管从逻辑上讲,它完全等同于简单地声明两个重载,在标头中采用 polymorphic_[io]archive&amp; 并在同一个 TU 中实现它们


    ¹ 库内部是否依赖 T::serialize&lt;&gt; 作为模板,而不是仅仅让 C++ 重载解析完成其工作

    奖金

    结合了其中一些想法的演示:Live On Wandbox

    1. 辅助.h

      #pragma once
      
      class A;
      class B;
      
      #include <memory>
      
      typedef std::shared_ptr<A> A_ptr;
      typedef std::shared_ptr<B> B_ptr;
      
      namespace boost { namespace serialization { class access; } }
      
    2. 啊.h

      #pragma once
      #include "auxiliary.h"
      
      class A {
        public:
          B_ptr bpt;
          void foo();
      
        private:
          friend class boost::serialization::access;
          template <class Archive> void serialize(Archive&, unsigned);
      };
      
    3. B.h

      #pragma once
      #include "auxiliary.h"
      
      class B {
        public:
          A_ptr apt;
          void bar();
          //...
        private:
          friend class boost::serialization::access;
          template <class Archive> void serialize(Archive&, unsigned);
      };
      
    4. A.cpp

      // A.cpp
      #include "A.h"
      
      #include "B.h"
      void A::foo() {
          // implementation
          bpt = std::make_shared<B>();
      }
      
      template <class Archive>
      void A::serialize(Archive &ar, unsigned) 
      {
          ar & bpt; 
      }
      
      #include <boost/archive/text_iarchive.hpp>
      #include <boost/archive/text_oarchive.hpp>
      #include <boost/serialization/shared_ptr.hpp>
      #include "B.h" // required at point of instatiation
      template void A::serialize(boost::archive::text_iarchive&, unsigned);
      template void A::serialize(boost::archive::text_oarchive&, unsigned);
      
    5. B.cpp

      // B.cpp
      #include "B.h"
      
      #include <iostream>
      void B::bar() {
          // implementation
          std::cout << "Hello from B::bar()\n";
      }
      
      template <class Archive>
      void B::serialize(Archive &ar, unsigned) 
      {
          ar & apt; 
      }
      
      #include <boost/archive/text_iarchive.hpp>
      #include <boost/archive/text_oarchive.hpp>
      #include <boost/serialization/shared_ptr.hpp>
      #include "A.h" // required at point of instatiation
      template void B::serialize(boost::archive::text_iarchive&, unsigned);
      template void B::serialize(boost::archive::text_oarchive&, unsigned);
      
    6. test.cpp

      #include <iostream>
      #include <sstream>
      
      void test_serialize(std::ostream&);
      void test_deserialize(std::istream&);
      
      int main() {
          std::stringstream ss;
      
          test_serialize(ss);
      
          std::cout << ss.str() << std::flush;
      
          test_deserialize(ss);
      }
      
      #include "auxiliary.h"
      #include <boost/archive/text_oarchive.hpp>
      #include "A.h"
      //#include "B.h" // optional, see below
      void test_serialize(std::ostream& os) {
          boost::archive::text_oarchive oa(os);
      
          A a1, a2;
          a1.foo();
          // a1.bpt->bar(); // only works if B.h included
          A a3 = a1; // copy, should alias a1.bpt and a3.bpt
          oa << a1 << a2 << a3;
      }
      
      #include <boost/archive/text_iarchive.hpp>
      #include "B.h" // optional, see below
      void test_deserialize(std::istream& is) {
          boost::archive::text_iarchive ia(is);
      
          A a1, a2, a3;
          ia >> a1 >> a2 >> a3;
      
          std::cout << std::boolalpha;
          std::cout << "B correctly deserialized: " << (a1.bpt && !a2.bpt) << "\n";
          std::cout << "Correctly aliased a1.bpt == a3.bpt: " << (a1.bpt == a3.bpt) << "\n";
      
          a3.bpt->bar(); // only works if B.h included
      }
      

    打印

    /home/sehe/custom/boost_1_65_0/boost/archive/detail/oserializer.hpp:467:22: runtime error: reference binding to null pointer of type 'const struct A'
    /home/sehe/custom/boost_1_65_0/boost/archive/detail/oserializer.hpp:467:22: runtime error: reference binding to null pointer of type 'const struct B'
    22 serialization::archive 15 1 0
    0 0 1 2 1 0
    1 0 1 -1
    2 -1
    3 2 1
    /home/sehe/custom/boost_1_65_0/boost/archive/detail/iserializer.hpp:540:19: runtime error: reference binding to null pointer of type 'struct B'
    /home/sehe/custom/boost_1_65_0/boost/archive/detail/iserializer.hpp:541:67: runtime error: reference binding to null pointer of type 'const struct B'
    B correctly deserialized: true
    Correctly aliased a1.bpt == a3.bpt: true
    Hello from B::bar()
    

    【讨论】:

    • 添加了bonus live demo
    • 感谢您为此付出的所有努力!!!我会立即尝试调整我的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    相关资源
    最近更新 更多