Hi,

I'm having some trouble using the Serialization library with a class derived from an abstract template (example code below).  What I'd like to do is serialize instances of the derived type through a base class pointer (polymorphic) using the XML archive.  The code below works fine using both the text and binary archives, but fails at runtime with the XML archive.  The exception thrown is boost::archive::xml_archive_exception with the message "uninitialized exception".

My environment:
GCC 4.1.2 on RHEL 5.3
Boost v1.37

I've also attempted to use Boost 1.40 (although I didn't see anything to suggest relevant changes), which results in link errors (undefined references to members of boost::archive::detail::archive_serializer_map<boost::archive::xml_iarchive> and boost::serialization::void_cast_detail::void_caster among others).

Any help would be appreciated.  Thanks.


#include <iostream>
#include <string>
#include <sstream>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/export.hpp>

class AbstractBase
{
public:
  AbstractBase(const std::string& n):name(n) {}
  virtual ~AbstractBase() {}

  virtual std::ostream& print(std::ostream& os) const = 0;

protected:
  AbstractBase():name("UNKNOWN BASE") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t version)
  {
    ar & BOOST_SERIALIZATION_NVP(name);
  }

  std::string name;
};

template <class T>
class AbstractTemplate : public AbstractBase
{
public:
  AbstractTemplate(const std::string& n):AbstractBase(n) {}
  virtual ~AbstractTemplate() {}

  virtual void doSomething(const T& t) = 0;

protected:
  AbstractTemplate():AbstractBase("UKNOWN TEMPLATE") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t version)
  {
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractBase);
  }
};

class Derived : public AbstractTemplate<std::string>
{
public:
  Derived(const std::string& n):AbstractTemplate<std::string>(n) {}
  virtual ~Derived() {}

  std::ostream& print(std::ostream& os) const { return os << "Derived name: " << name << std::endl; }

  void doSomething(const std::string& str) { print(std::cout << str << ": "); }

protected:
  Derived():AbstractTemplate<std::string>("UNKNOWN DERIVED") {}

  friend class boost::serialization::access;
  template<class Archive> void serialize(Archive& ar, const uint32_t version)
  {
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AbstractTemplate<std::string>);
  }
};

BOOST_CLASS_EXPORT(Derived)

namespace boost {

template <>
struct is_abstract<AbstractBase >
{
  typedef mpl::bool_<true> type;
  BOOST_STATIC_CONSTANT(bool, value = true);
};

template<class T>
struct is_abstract<AbstractTemplate<T> >
{
  typedef mpl::bool_<true> type;
  BOOST_STATIC_CONSTANT(bool, value = true);
};

}  // namepsace boost

int main(int argc, char** argv)
{
  static const char XML_NAME[] = "Stuff";

  Derived* d = new Derived("test 1");
  AbstractTemplate<std::string>* at = d;
  AbstractBase* ab = d;

  std::cout << "before serialization:" << std::endl;
  d->doSomething("something");
  at->print(std::cout);
  ab->print(std::cout);

  /* serialization */
  std::stringstream ss;

  {
    boost::archive::xml_oarchive xmlOut(ss);
    xmlOut << boost::serialization::make_nvp(XML_NAME, ab);
  }

  delete ab;
  ab = NULL;

  std::cout << "Serialization:" << std::endl
        << ss.str() << std::endl;

  /* deserialization */
  {
    boost::archive::xml_iarchive xmlIn(ss);
    xmlIn >> boost::serialization::make_nvp(XML_NAME, ab);
  }

  at = dynamic_cast<AbstractTemplate<std::string>*>(ab);
  d = dynamic_cast<Derived*>(ab);

  if ((ab == NULL)
    || (at == NULL)
    || (d == NULL))
  {
    std::cout << "deserialization failed" << std::endl;
    return EXIT_FAILURE;
  }

  std::cout << "after deserialization:" << std::endl;
  d->doSomething("something");
  at->print(std::cout);
  ab->print(std::cout); 
  delete ab;

  return EXIT_SUCCESS;
}