tags:

views:

118

answers:

2

Hi,

I was looking at the boost serialization library, and the intrusive way to provide support for serialization is to define a member function with signature (simplifying):

class ToBeSerialized {
public:
    //Define this to support serialization
    //Notice not virtual function!
    template<class Archive>
    void serialize(Archive & ar)
    {.....}
};

Moreover, one way to support serilization of derived class trough base pointers is to use a macro of the type:

//No mention to the base class(es) from which Derived_class inherits
BOOST_CLASS_EXPORT_GUID(Derived_class, "derived_class")

where Derived_class is some class which is inheriting from a base class, say Base_class. Thanks to this macro, it is possible to serialize classes of type Derived_class through pointers to Base_class correctly.

The question is: I am used in C++ to write abstract factories implemented through a map from std::string to (pointer to) functions which return objects of the desired type (and eveything is fine thanks to covariant types).

Hover I fail to see how I could use the above non-virtual serialize template member function to properly de-serialize (i.e. construct) an object without knowing its type (but assuming that the type information has been stored by the serializer, say in a string).

What I would like to do (keeping the same nomenclature as above) is something like the following:

XmlArchive xmlArchive; //A type or archive
xmlArchive.open("C:/ser.txt"); //Contains type information for the serialized class
Base_class* basePtr = Factory<Base_class>::create("derived_class",xmlArchive);

with the function on the righ-hand side creating an object on the heap of type Derived_class (via default constructor, this is the part I know how to solve) and calling the serialize function of xmlArchive (here I am stuck!), i.e. do something like:

Base_class* Factory<Base_class>::create("derived_class",xmlArchive)
{
    Base_class* basePtr = new Base_class; //OK, doable, usual map string to pointer to function
    static_cast<Derived_class*>( basePtr )->serialize( xmlArchive ); //De-serialization, how?????
    return basePtr;
}

I am sure this can be done (boost serialize does it but its code is impenetrable! :P), but I fail to figure out how. The key problem is that the serialize function is a template function. So I cannot have a pointer to a generic templated function. As the point in writing the templated serialize function is to make the code generic (i.e. not having to re-write the serialize function for different Archivers), it does not make sense then to have to register all the derived classes for all possible archive types, like:

MY_CLASS_REGISTER(Derived_class, XmlArchive);
MY_CLASS_REGISTER(Derived_class, TxtArchive);
...

In fact in my code I relies on overloading to get the correct behaviour:

void serialize( XmlArchive& archive, Derived_class& derived );
void serialize( TxtArchive& archive, Derived_class& derived );
...

The key point to keep in mind is that the archive type is always known, i.e. I am never using runtime polymorphism for the archive class...(again I am using overloading on the archive type).

Any suggestion to help me out?

Thank you very much in advance!

Cheers

A: 

If your archive type is always known, why bother parameterizing your serialize function on it? There's an argument to be made for code reuse, yes, but if your Archive class ever changes its definition or gets replaced, you will likely need to refactor some of your serialization code anyway.

If you stick with:

class ToBeSerialized : public Base_class {
public:
    void serialize(Archive & ar)
    {.....}
};

You can then take a pointer to your serialize function, and bind it to your factory.

You will also need to bind separate create functions for each class, so that it can instantiate the right type when it's asked for it. Something like:

template <typename T> Base_class* Factory::create(Archive& xmlArchive) {
    T* derivedPtr = new T;
    derivedPtr->serialize( xmlArchive );
    return derivedPtr;
}

The factory will then need a generic create method that calls out to the correct static parameterized create<T>:

Base_class* Factory::create(const char* typeString, Archive& xmlArchive) {
    // Pseudocode.
    return m_map.find(typeString)->callCreate(xmlArchive);
}
Blair Holloway
The problem I have is exactly that the archive type is explicit but not fixed, I can have say a Xml arhive, a binary archive, and so on...The point here is that the serialize function is quite a stupid one, example:template<class A>void serialize( Aserialize( a, m_double, "m_double" );} In fact it just lists the data members that needs to be serialized and associate a string to each of them.Then serialize( a, m_int, "m_int" ) do the serialization based on the types of a (the archive) and m_int (say an int to be serialized).Sorry for confusion.
KRao
A: 
Noah Roberts
But how do I make this code generic with respect to the type of xmlArchive?I would like to have a single registration (macro as boost, or function better) for each derived class, and have each type of archive being able to do what it needs based on the information provided by this registration only.Thank you for your help anyway!
KRao
Just alter the concepts above to be templated based on the archive too. No big deal.
Noah Roberts