提升前向声明类的序列化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了提升前向声明类的序列化相关的知识,希望对你有一定的参考价值。
我想将具有彼此的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
我尝试了各种方法,但没有成功。
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
- 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;
- 啊
#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); ;
- 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); ;
- 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);
- 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);
- 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()
以上是关于提升前向声明类的序列化的主要内容,如果未能解决你的问题,请参考以下文章