Boost C++ Libraries: Ticket #7047: Deriving custom archive classes from boost::archive::text_oarchive_impl and boost::archive::text_iarchive_impl https://svn.boost.org/trac10/ticket/7047 <p> From here<a class="ext-link" href="http://stackoverflow.com/questions/10691911/deriving-custom-archive-classes-from-boostarchivetext-oarchive-impl-and-boos"><span class="icon">​</span>http://stackoverflow.com/questions/10691911/deriving-custom-archive-classes-from-boostarchivetext-oarchive-impl-and-boos</a> </p> <p> Summary: After changing the base classes of my custom archives from binary_?archive_impl to text_?archive_impl, my custom archive classes are no longer "found" when the compiler is instantiating the serialize(...) methods in my other classes. </p> <p> Background: My application was successfully reading and writing files to disk using subclasses of binary_?archive_impl (the documentation and/or code comments recommend this over deriving from binary_?archive). I needed to switch from a binary file format to a text format, so I switched the base classes of my custom archives to text_?archive_impl. That's when everything blew up. </p> <p> The problem: My custom archive classes add functionality, including some additional methods which do not exist in their Boost base classes; these methods are called in the serialize(...) methods in many of my classes, and they were working fine. After changing the base classes from binary_?archive_impl to text_?archive_impl, I received compilation errors all over the place complaining that my custom methods do not exist in text_?archive. Well, that's obvious (!!!), but they do exist in my custom archives, and they were working just fine when I was using Boost's binary base classes. What's the deal? </p> <p> What I found, and my temporary - but undesirable - solution: After tearing my hair out and going around in circles for about a day, this is what I found... </p> <p> 1) Some time ago (Boost 1.34 I believe), the files "binary_?archive.hpp" were split up into "binary_?archive_impl.hpp" and "binary_?archive.hpp" (the latter #include the former). This was not done to "text_?archive.hpp". (As a result, I changed my application's #include lines from "binary_?archive_impl.hpp" to simply "text_?archive.hpp".) </p> <p> 2) If I split up "text_?archive.hpp" into two parts and #include only the "..._impl.hpp" headers, everything works. (But I really don't want to modify my Boost installation!) </p> <p> 3) Looking more closely at these headers and fiddling around a bit, I found that if I use the original, unmodified headers and comment out the line </p> <p> BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::text_oarchive) </p> <p> (and likewise for text_iarchive), then everything works fine again. (By the way I have similar lines in my own archive code to "register" my custom archives.) </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7047 Trac 1.4.3 Robert Ramey Sun, 21 Oct 2012 20:48:59 GMT <link>https://svn.boost.org/trac10/ticket/7047#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7047#comment:1</guid> <description> <p> I would really like a better explanation of this along with a specific recommendation as to what should be changed. </p> <p> You might want to post your code for your custom archive. </p> <p> Hopefully this would end up being some misunderstanding or missing information which is needed to properly support a custom archive. Ideally this would be crafted as an example to be added to the package. </p> <p> I'm thinking that the missing magic is: </p> <p> BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::custom_oarchive) </p> <p> but that's just a guess. </p> <p> I'll leave this ope a little while longer to give you a chance to respond. </p> <p> Robert Ramey </p> </description> <category>Ticket</category> </item> <item> <author>zachais.vawter@…</author> <pubDate>Tue, 30 Oct 2012 20:06:53 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7047#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7047#comment:2</guid> <description> <p> Robert, </p> <p> A co-worker or I would like to submit a patch for this issue, but we don't have time at the moment. </p> <p> Point 3 above addresses the use of BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::custom_oarchive) does not fix the issue unless we remove the BOOST_SERIALIZATION_REGISTER_ARCHIVE(boost::archive::text_oarchive) line from the text archive headers. </p> <p> I believe the correct fix is listed in point 1. </p> <p> -Zac </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Sat, 24 Aug 2013 14:09:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/7047#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7047#comment:3</guid> <description> <p> I had the same problem tying to implement custom archive for my library. I've found a possible solution trick, it seems to works well so I'll share with you: </p> <p> There is no way to export a class with a modified serialization syntax in boost archive, so we have to avoid it at all. </p> <p> boost archive registration uses a properly overloaded function to make a pointer serialization type instance ( as in boost/archive/detail/register_archive.hpp ) </p> <pre class="wiki"># define BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive) \ namespace boost { namespace archive { namespace detail { \ \ template &lt;class Serializable&gt; \ BOOST_DEDUCED_TYPENAME _ptr_serialization_support&lt;Archive, Serializable&gt;::type \ instantiate_ptr_serialization( Serializable*, Archive*, adl_tag ); \ \ } } } </pre><p> Note that adl_tag adds a cool overload feature that can be used to make boost able to look inside our implementation. Simply put a new registration declaration as this: </p> <pre class="wiki">// ARCHIVES REGISTRATION // namespace MyLib { struct adl_tag {}; } namespace boost { namespace archive { namespace detail { template &lt;class Serializable&gt; void instantiate_ptr_serialization(Serializable*, int, MyLib::adl_tag ) {} } } } # define MYLIB_SERIALIZATION_REGISTER_ARCHIVE(_Archive) \ namespace boost { namespace archive { namespace detail { \ template &lt;class Serializable&gt; \ BOOST_DEDUCED_TYPENAME _ptr_serialization_support&lt;_Archive, Serializable&gt;::type \ instantiate_ptr_serialization( Serializable*, _Archive*, MyLib::adl_tag ); } } } </pre><p> Now you have to make your own EXPORT macro as in (/boost/serialization/export.hpp): </p> <pre class="wiki">namespace MyLib { namespace extra_detail { template&lt;class T&gt; struct guid_initializer { void export_guid(mpl::false_) const { // generates the statically-initialized objects whose constructors // register the information allowing serialization of T objects // through pointers to their base classes. boost::archive::detail:: instantiate_ptr_serialization((T*)0, 0, MyLib::adl_tag()); } void export_guid(mpl::true_) const { } guid_initializer const &amp; export_guid() const { BOOST_STATIC_WARNING(boost::is_polymorphic&lt; T &gt;::value); // note: exporting an abstract base class will have no effect // and cannot be used to instantitiate serialization code // (one might be using this in a DLL to instantiate code) //BOOST_STATIC_WARNING(! boost::serialization::is_abstract&lt; T &gt;::value); export_guid(boost::serialization::is_abstract&lt; T &gt;()); return *this; } }; template&lt;typename T&gt; struct init_guid; } // extra_detail } // namespace MyLib #define MYLIB_CLASS_EXPORT_IMPLEMENT(T) \ namespace MyLib { \ namespace extra_detail { \ template&lt;&gt; \ struct init_guid&lt; T &gt; { \ static guid_initializer&lt; T &gt; const &amp; g; \ }; \ guid_initializer&lt; T &gt; const &amp; init_guid&lt; T &gt;::g = \ ::boost::serialization::singleton&lt; \ guid_initializer&lt; T &gt; \ &gt;::get_mutable_instance().export_guid(); \ }} \ /**/ </pre><p> Ok it's all, now you can define your custom archive and register it with: </p> <pre class="wiki">MYLIB_SERIALIZATION_REGISTER_ARCHIVE(MyLib::xml_iarchive) </pre><p> and anytime you define a serialization for your class that has a particular syntax only readable by MyLib::custom_archive you can use your export implementation </p> <pre class="wiki">BOOST_CLASS_EXPORT_KEY(MyClass) // in header MYLIB_CLASS_EXPORT_IMPLEMENT(MyClass) // in cpp </pre><p> (Note that exporting of Key remains the same of boost ... ) </p> <p> This is really cool because lets your custom archives and boost archives live together without errors.. Anytime you wants a boost serialization simply use BOOST_CLASS_EXPORT, and anytime you have your class to be serialized use MYLIB_CLASS_EXPORT. </p> <p> Hope that this could be useful ! </p> <p> Andrea Rigoni Garola (OpenCMT - Cosmic Muon Tomography library) </p> </description> <category>Ticket</category> </item> </channel> </rss>