Confused about serialization

I don't understand why this simple test doesn't compile. Any hints? #include <iostream> #include <sstream> #include <boost/archive/binary_oarchive.hpp> #include <boost/archive/binary_iarchive.hpp> class rng_t { public: friend class boost::serialization::access; // BOOST_SERIALIZATION_SPLIT_MEMBER() template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < 10; ++j) // ar << compute(j); ar << int(0); } template<class Archive> inline void load (Archive &ar, const unsigned int) { } template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::split_member(ar, *this, file_version); } }; void getstate (const rng_t& rng) { std::ostringstream os; boost::archive::binary_oarchive oa(os); oa << rng; } void setstate (rng_t& rng, std::string& st) { std::istringstream is (st); boost::archive::binary_iarchive ia (is); ia >> rng; } g++ -c test.cc test.cc: In member function ‘void rng_t::save(Archive&, unsigned int) const [with Archive = boost::archive::binary_oarchive]’: /usr/include/boost/serialization/access.hpp:93: instantiated from ‘static void boost::serialization::access::member_save(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = const rng_t]’ /usr/include/boost/serialization/split_member.hpp:43: instantiated from ‘static void boost::serialization::detail::member_saver<Archive, T>::invoke(Archive&, const T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = rng_t]’ /usr/include/boost/serialization/split_member.hpp:69: instantiated from ‘void boost::serialization::split_member(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = rng_t]’ test.cc:25: instantiated from ‘void rng_t::serialize(Archive&, unsigned int) [with Archive = boost::archive::binary_oarchive]’ /usr/include/boost/serialization/access.hpp:109: instantiated from ‘static void boost::serialization::access::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = rng_t]’ /usr/include/boost/serialization/serialization.hpp:81: instantiated from ‘void boost::serialization::serialize(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = rng_t]’ /usr/include/boost/serialization/serialization.hpp:140: instantiated from ‘void boost::serialization::serialize_adl(Archive&, T&, unsigned int) [with Archive = boost::archive::binary_oarchive, T = rng_t]’ /usr/include/boost/archive/detail/oserializer.hpp:147: instantiated from ‘void boost::archive::detail::oserializer<Archive, T>::save_object_data(boost::archive::detail::basic_oarchive&, const void*) const [with Archive = boost::archive::binary_oarchive, T = rng_t]’ test.cc:37: instantiated from here test.cc:16: error: no match for ‘operator<<’ in ‘ar << 0’ /usr/include/boost/archive/detail/interface_oarchive.hpp:84: note: candidates are: Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = int, Archive = boost::archive::binary_oarchive]

Neal Becker wrote:
I don't understand why this simple test doesn't compile. Any hints?
[...]
test.cc:16: error: no match for ‘operator<<’ in ‘ar << 0’ /usr/include/boost/archive/detail/interface_oarchive.hpp:84: note: candidates are: Archive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = int, Archive = boost::archive::binary_oarchive]
It seems an lvalue is required, which you don't provide, just a temporary. Regards, Stefan

Neal Becker wrote:
I don't understand why this simple test doesn't compile. Any hints? ... template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < 10; ++j) // ar << compute(j); ar << int(0); }
The above would be a problem. Serialization operators use reference to data as arguments. An object pushed on the stack has no permanent address. So it can't be serialized.
template<class Archive> inline void load (Archive &ar, const unsigned int) { }
suppose you made the above work by doing something like: const int x = 0; ar << x; If the above did work - that is if it inserted a 0 value into the archive, then what would loading mean? So the question is - what is the intention here? Robert Ramey

Actually, I am trying to improve my serialization of mersenne_twister, and the previous test was a useless test to debug it. I have gotten a little further now, I think I have the "save" correct. I'm not sure about "load". I have been trying to follow the example of collections_load_imp. It uses "stack_construct" and "reset_object_address". I'm having trouble finding where the use of these is documented and whether I need them for my case. So far the mersenne_twister relevant code would look like: (In MT, compute() returns the elements we want to save, and to restore we just load the array 'x' directly.) template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < state_size; ++j) { UIntType x = compute (j); ar << boost::serialization::make_nvp("item", const_cast<const UIntType&>(x)); } } template<class Archive> inline void load (Archive &ar, const unsigned int) { for (int j = 0; j < state_size; ++j) { stack_contruct<Archive, UIntType> t (ar); ar >> boost::serialization::make_nvp ("item", t.reference()); x[j] = t.reference(); ar.reset_object_address (??? } i = state_size; } template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::split_member(ar, *this, file_version); }

I think this is OK now. Here is addition to mersenne_twister.hpp: friend class boost::serialization::access; template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < state_size; ++j) { UIntType x = compute (j); ar << boost::serialization::make_nvp("item", const_cast<const UIntType&>(x)); } } template<class Archive> inline void load (Archive &ar, const unsigned int) { for (int j = 0; j < state_size; ++j) { ar >> boost::serialization::make_nvp ("item", x[j]); } i = state_size; } template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::split_member(ar, *this, file_version); } Also: #include <boost/serialization/split_member.hpp> #include <boost/serialization/nvp.hpp> Here is a simple test that passes: #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/random.hpp> typedef boost::mt19937 rng_t; int main() { rng_t rng1; std::ostringstream os; boost::archive::text_oarchive oa(os); oa << const_cast<const rng_t&>(rng1); std::string st (os.str()); std::istringstream is (st); boost::archive::text_iarchive ia (is); rng_t rng2; ia >> rng2; // std::cout << rng2; assert (rng1 == rng2); }

Hmm - this raises a couple of questions in my mind. I would guess this is because I don't kow what the meserenne twister does. First a slight cosmetic change just to avoid a confusing/ugly cast; template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < state_size; ++j) { const UIntType x = compute (j); ar << boost::serialization::make_nvp("item", x); } } But I'm intrigued about one thing. It seems to me that if you have an instance of the class meserenne twister and serialize it to a file then load it back to another instance - the two wont be equal unless compute(j) == j ? What am I missing here? Neal Becker wrote:
I think this is OK now. Here is addition to mersenne_twister.hpp: friend class boost::serialization::access;
template<class Archive> inline void save (Archive &ar, const unsigned int) const { for (int j = 0; j < state_size; ++j) { UIntType x = compute (j); ar << boost::serialization::make_nvp("item", const_cast<const UIntType&>(x)); } }
template<class Archive> inline void load (Archive &ar, const unsigned int) { for (int j = 0; j < state_size; ++j) { ar >> boost::serialization::make_nvp ("item", x[j]); } i = state_size; }
template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::split_member(ar, *this, file_version); }
Also: #include <boost/serialization/split_member.hpp> #include <boost/serialization/nvp.hpp>
Here is a simple test that passes:
#include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/random.hpp>
typedef boost::mt19937 rng_t;
int main() { rng_t rng1;
std::ostringstream os; boost::archive::text_oarchive oa(os); oa << const_cast<const rng_t&>(rng1);
std::string st (os.str()); std::istringstream is (st); boost::archive::text_iarchive ia (is); rng_t rng2; ia >> rng2;
// std::cout << rng2; assert (rng1 == rng2); }
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Robert Ramey wrote: [...]
But I'm intrigued about one thing. It seems to me that if you have an instance of the class meserenne twister and serialize it to a file then load it back to another instance - the two wont be equal unless compute(j) == j ?
What am I missing here?
friend bool operator==(const mersenne_twister& x, const mersenne_twister& y) { for(int j = 0; j < state_size; ++j) if(x.compute(j) != y.compute(j)) return false; return true; } I don't understand why you say that. It compares == if the states are == over the stat_size. Isn't that correct?
participants (3)
-
Neal Becker
-
Robert Ramey
-
Stefan Seefeld