Question

I have a virtual template class and a derived class. I'm trying now to use boost::serialisation for the derived class. This is my code so far:

template <class T> class classOne { 
public:     
    classOne(){};   
    classOne(T val) : st(val){};    
    virtual ~classOne() {};     
    virtual double GetError() =0; 
protected:  T st;
private:
    friend class boost::serialization::access;
    template<class archive>
    void serialize(archive& ar, const unsigned int version)
    {
         ar & BOOST_SERIALIZATION_NVP(st);
    }
}; 
BOOST_SERIALIZATION_ASSUME_ABSTRACT(classOne<double>);

template <class T> class classTwo : public classOne<T>
{
public:
    classTwo() : classOne<T>(1.0), error(0){};
    classTwo(T val) : classOne<T>(val), error(val){};
    virtual T GetError() {return error;};

private:
    T error;
    friend class boost::serialization::access;
    template<class archive>
    void serialize(archive& ar, const unsigned int version)
    {
            ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(classOne<T>);
            ar & BOOST_SERIALIZATION_NVP(error);
    }
};
int main(int argc, char** argv){
   classTwo<double> ch2(0.5);
   std::ofstream ofs2("test2.xml");
   boost::archive::xml_oarchive oa2(ofs2);
   oa2 << BOOST_SERIALIZATION_NVP(ch2);
   ofs2.close();
}

The code compiles but at runtime i get:

terminate called after throwing an instance of 'boost::archive::xml_archive_exception'
    what():  Invalid XML tag name

When classOne is not template class everything works. Can somebody help?

Was it helpful?

Solution

Well, the problem is quite obvious: <> don't go well inside XML element tags.

So, here's what you I naively thought of to fix it.

ar & boost::serialization::make_nvp(
      "base", static_cast<classOne<T>&>(*this));

IMPORTANT UPDATE However, just today, I stumbled across the documentation here:

Note the serialization of the base classes from the derived class. Do NOT directly call the base class serialize functions. Doing so might seem to work but will bypass the code that tracks instances written to storage to eliminate redundancies. It will also bypass the writing of class version information into the archive. For this reason, it is advisable to always make member serialize functions private.

Oops. So here's the new and correct advice:

    typedef classOne<T> baseClass;
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(baseClass);

Now, you control the name of the xml element by working with the macro and using a typedef to hide the brackets.

Output:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="10">
<ch2 class_id="0" tracking_level="0" version="0">
    <baseClass class_id="1" tracking_level="0" version="0">
        <st>0.5</st>
    </baseClass>
<error>0.5</error>
</ch2>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top