提升前向声明类的序列化

问题描述 投票:1回答:1

我想将具有彼此的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”:不允许将未定义的类作为编译器内部类型的参数__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个回答
0
投票

Boost Serialization Archives是编译时多态的。这意味着它们结合了类和功能模板中的功能,这些模板定义了各个类型和行为。

由于C ++中模板的性质,这意味着您需要在POI(实例化点)处完整定义这些模板(及其依赖类型)。 (参见Why can templates only be implemented in the header file?的底漆)。

解?

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

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

注意:文档示例将serialize成员显示为模板函数,该函数在单个TU中显式实例化。这可能是出于技术原因需要¹,虽然从逻辑上说它完全等同于简单地声明两个重载,在标题中使用polymorphic_[io]archive&并在同一个TU中实现它们


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

BONUS

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

  1. auxiliary.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. #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()
© www.soinside.com 2019 - 2024. All rights reserved.