我希望将具有彼此的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&#34; A&#34;:不允许将未定义的类作为编译器内部类型的参数__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
我尝试了各种方法,但没有成功。
答案 0 :(得分: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 ++重载解析完成其工作
结合其中一些想法的演示: Live On Wandbox
#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);
};
#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
#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
#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);
#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()