// #pragma warning( disable: 4511 ) // #pragma warning( disable: 4512 ) #include #include #include #include #include #include #include #include std::map< boost::shared_ptr, int > sp_save_map; std::map< int, std::pair< boost::shared_ptr, std::type_info const * > > sp_load_map; class typeinfo { public: typeinfo( std::type_info const & ti = typeid(void) ): pti_( &ti ) { } friend inline bool operator==( typeinfo const & a, typeinfo const & b ) { return *a.pti_ == *b.pti_? true: false; } friend inline bool operator!=( typeinfo const & a, typeinfo const & b ) { return !( *a.pti_ == *b.pti_ ); } friend inline bool operator<( typeinfo const & a, typeinfo const & b ) { return a.pti_->before( *b.pti_ )? true: false; } std::type_info const * operator->() const { return pti_; } private: std::type_info const * pti_; }; typedef std::pair typeinfo_pair; typedef boost::shared_ptr Pv; typedef std::map< typeinfo_pair, Pv (*) (Pv) > upcast_map_type; upcast_map_type upcast_map; template< class B > boost::shared_ptr upcast( boost::shared_ptr pvd, typeinfo const & dti ) { typeinfo bti( typeid(B) ); if( bti == dti ) { return boost::static_pointer_cast( pvd ); } typeinfo_pair k( bti, dti ); upcast_map_type::const_iterator i = upcast_map.find( k ); if( i != upcast_map.end() ) { return boost::static_pointer_cast( i->second( pvd ) ); } else { throw std::logic_error( std::string("shared_ptr conversion from '") + typeid(B).name() + "' to '" + dti->name() + "' not registered." ); } } template< class B, class D > struct upcast_converter { static boost::shared_ptr f( boost::shared_ptr pvd ) { boost::shared_ptr pd = boost::static_pointer_cast( pvd ); boost::shared_ptr pb( pd ); return pb; } }; template< class B, class D > void register_conversion() { typeinfo_pair k( typeid(B), typeid(D) ); upcast_map[ k ] = upcast_converter::f; } template boost::shared_ptr most_derived( boost::shared_ptr const & pt, boost::mpl::true_ ) { return boost::dynamic_pointer_cast( pt ); } template boost::shared_ptr most_derived( boost::shared_ptr const & pt, boost::mpl::false_ ) { return pt; } namespace boost { template void save( A & a, shared_ptr const & pt, unsigned /* v */ ) { if( pt ) { int pid = sp_save_map[ pt ]; if( pid != 0 ) { a << BOOST_SERIALIZATION_NVP( pid ); } else { pid = - static_cast( sp_save_map.size() ); sp_save_map[ pt ] = pid; a << BOOST_SERIALIZATION_NVP( pid ); T * px = pt.get(); a << BOOST_SERIALIZATION_NVP( px ); } } else { int pid = 0; a << BOOST_SERIALIZATION_NVP( pid ); } } template void load( A & a, shared_ptr & pt, unsigned /* v */ ) { int pid; a >> BOOST_SERIALIZATION_NVP( pid ); if( pid == 0 ) { pt.reset(); } else { if( sp_load_map.count( pid ) ) { pt = upcast( sp_load_map[ pid ].first, *sp_load_map[ pid ].second ); } else { T * px; a >> BOOST_SERIALIZATION_NVP( px ); pt.reset( px ); sp_load_map[ pid ].first = most_derived( pt, is_polymorphic() ); sp_load_map[ pid ].second = &typeid( *px ); } } } template inline void serialize( A & a, shared_ptr & pt, unsigned v ) { boost::serialization::split_free( a, pt, v ); } } // namespace boost #include #include struct prefix { int w_; explicit prefix( int w ): w_( w ) { } virtual ~prefix() { } template void serialize( Archive & ar, unsigned /* file_version */ ) { ar & BOOST_SERIALIZATION_NVP( w_ ); } virtual void print() const { std::cout << "{ " << w_ << " } "; } }; struct base { int x_; explicit base( int x = 0 ): x_( x ) { } virtual ~base() { } template void serialize( Archive & ar, unsigned /* file_version */ ) { ar & BOOST_SERIALIZATION_NVP( x_ ); } virtual void print() const { std::cout << "{ " << x_ << " } "; } }; struct derived: public prefix, public base { int y_; explicit derived( int w = 0, int x = 0, int y = 0 ): prefix( w ), base( x ), y_( y ) { } template void serialize( Archive & ar, unsigned /*file_version*/ ) { ar & boost::serialization::make_nvp( "prefix", boost::serialization::base_object( *this ) ); ar & boost::serialization::make_nvp( "base", boost::serialization::base_object( *this ) ); ar & BOOST_SERIALIZATION_NVP( y_ ); } virtual void print() const { std::cout << "{ "; prefix::print(); base::print(); std::cout << y_ << " } "; } }; #include #include #include #include #include #include #include #include #include #include #include #include BOOST_CLASS_EXPORT_GUID( derived, "derived" ) int main() { register_conversion(); try { std::stringstream ss; { boost::archive::xml_oarchive ar( ss ); // ( std::cerr ); std::vector< boost::shared_ptr > v; boost::shared_ptr pb( new derived( 42, 1337, 31337 ) ); boost::shared_ptr pb2( new derived( 7, 8, 9 ) ); boost::shared_ptr pb3( new base( 11 ) ); v.push_back( pb ); v.push_back( pb3 ); v.push_back( pb ); v.push_back( pb2 ); v.push_back( pb ); v.push_back( pb3 ); std::for_each( v.begin(), v.end(), boost::mem_fn( &base::print ) ); std::cout << "\n\n--\n\n"; ar << BOOST_SERIALIZATION_NVP( v ); } std::cout << ss.str() << "\n\n--\n\n"; { boost::archive::xml_iarchive ar( ss ); std::vector< boost::shared_ptr > v; ar >> BOOST_SERIALIZATION_NVP( v ); std::for_each( v.begin(), v.end(), boost::mem_fn( &base::print ) ); std::cout << "\n"; } } catch( std::exception const & x ) { std::cout << "Exception(" << typeid(x).name() << "): " << x.what() << std::endl; } }