As my prveious question sounded confusing, I think it's best to clearly state what I want to achieve.
I have (ignore the inheritance for now and focus on X):
class Base {};
class X : public Base {
private:
double m_double;
public:
template<class A> friend
void state( A& a, const X& x ) {
data( a, x.m_double, "m_double" );
}
};
I can now introduce arbitrary new classes that performs different actions based on how the data function is overloaded, we will refer to these as Accessors in the following:
class XmlArchive {...}; //One Accessor
template<class T>
void data( XmlArchive& a, const T& t, const std::string& str ) {
//read data and serialize it to xml Archive
}
class ParameterList {...}; //Another Accessor
template<class T>
void data( ParameterList& a, const T& t, const std::string& str ) {
//put data in a parameter list
}
I can then write:
X myX;
XmlArchive myArchive;
state( myArchive, myX );
ParameterList myParameters;
state( myParameters, myX );
Fantastic, code reuse! :D However the following (clearly) fails:
Base* basePtr = new X; //This would come from factory really, I should not know the type X
state( myParameters, *basePtr ); //Error
The goal is to make this last call succed. What I have considered (and why it is not acceptable):
First option: make all Accessors inherit from a common base class, say AccessorBase, then write in Base
virtual state( AccessorBase& a ) const = 0;
and implement the required code in X (the syntax to call state will be marginally different but this can be fixed). The problem is that AccessorBase will need to have a virtual function for every possible type which comes as second argument in the data function(s). As these types can be user-defined classes (see case of class composition, X which has Y as data member) I do not see how to make this strategy can work.
Second option: create a virtual function in Base for every Accessor. This violates the open/close principle as adding a new Accessor class (say TxtArchive) will require modification of the base class.
I understand why virtual member function cannot be templated (possible different vtbls in different compilation units). However it seemes to me that there should be a solution to this problem... Base knows that it really is of type X, and the type of the Accessor is always explicit, so it is a matter of finding a way of calling (for Accessor of type XmlArchive):
state( xmlArchive, x ); //xmlArchive of type XmlArchive, x of type X
which will yield the result.
To sum-up I would like the call:
state( myParameters, *basePtr );
to succeed if basePtr is pointing to a derived class with a function template compatible with the call and to throw an exception otherwise.
It seemes to me that boost::serialize does something similar but I cannot figure out how (it may be it is re-implemnting inheritance relationships in C++ via templates, I see a This() funcion returning the most derived pointer but it gets really confusing...)
Thank you again in advance for your help!