Is it possible to construct objects from directly from the archive?
Something like this...
// Non-working pseudo code
struct Foo {
BOOST_SERIALIZATION_SPLIT_MEMBER();
std::vector<int> data;
Foo() {
// populate "data" by doing calculation
data.push_back(1); data.push_back(2);
}
template<class Archive>
Foo( Archive & ar ) {
// populate "data" by rading the archive
}
template<class Archive>
void save(Archive & ar, const unsigned int version) const {
// Normal serialization of data
ar << data;
}
};
int main(int argc, const char *argv[])
{
// deserialize
boost::archive::text_iarchive oar(std::cin);
Foo foo(oar);
return 0;
}
You can use a deserializing constructor:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <fstream>
class Point
{
public:
Point() = default;
Point(boost::archive::text_iarchive& archive)
{
archive >> *this;
}
float x = 1.;
float y = 2.;
private:
friend class boost::serialization::access;
template<class TArchive>
void serialize(TArchive & archive, const unsigned int version)
{
archive & x;
archive & y;
}
};
int main()
{
Point p;
p.x = 5;
p.y = 6;
std::ofstream outputStream("test.archive");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << p;
outputStream.close();
std::ifstream inputStream("test.archive");
boost::archive::text_iarchive inputArchive(inputStream);
Point pointRead(inputArchive);
std::cout << pointRead.x << " " << pointRead.y << std::endl;
return 0;
}
As I said in the comment.
Yes there is no problem with constructing from an archive.
(Another alternative is to have static load
function but that can have performance penalties).
The only potential problem I see with your approach is that your constructor can take almost anything as an argument and that can create problems.
And that can interfere with the copy constructor and other single argument constructors relying in implicit conversion.
So one has to restrict to take archives only.
There are different methods to do this, but based in this conversation http://marc.info/?l=boost&m=121131260728308&w=2, and by the fact that the inheritance tree of the archives
is documented http://www.boost.org/doc/libs/1_35_0/libs/serialization/doc/class_diagram.html, I think this is the best solution is to check that the argument derives from basic_iarchive
.
#include<type_traits>
struct Foo {
...
std::vector<int> data;
Foo() {
// populate "data" by doing calculation
data.push_back(1); data.push_back(2);
}
template<class IArchive,
typename = std::enable_if_t<std::is_base_of<boost::archive::detail::basic_iarchive, IArchive>::value>>
Foo( IArchive & ar ) {
ar >> data;
// populate "data" by reading the archive
}
...
};
int main(int argc, const char *argv[])
{
// deserialize
boost::archive::text_iarchive iar(std::cin);
Foo foo(iar); // will also work with other archives
}
As for what happens when your data is not default constructive see the discussion above.