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
All you need is to store some sort of identifier before storing the information from the derived type. Then upon reading you use that identifier, which you've read first, to direct you to a factory that can then interpret the next block of information correctly and generate your derived type. This is probably what boost::serialization does at a very basic level. Maybe something like so:
ar >> type;
Base_class* basePtr = Factory<Base_class>::create(type,xmlArchive);
Then you have a map of objects that look something like so:
struct reader_base { virtual void load(xmlArchive, base_ptr) = 0; }
template < typename T >
struct reader : reader_base
{
virtual void load(xmlArchive, base_ptr)
{
static_cast<T*>(base_ptr)->serialize(xmlArchive);
}
};
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);
}
Related
I have implemented a pure C++11 Any class (based on this code) which is similar to boost::any and works nicely if used directly.
However I need to use this now as template parameter to assign parameters to variables. Look at this:
class A {
IRecognizer<Any, Any> *_recognizer;
template <typename T1, typename T2>
A(IRecognizer<T1, T2> *x) : _recognizer(x) {
}
}
and
template<typename Symbol, typename ATNInterpreter>
class IRecognizer {
public:
virtual int getState() = 0;
};
Even though I could assign each template parameter to an Any variable, I'm not allowed to assign IRecognizer<T1, T2> to IRecognizer<Any, Any>. Is there a solution for this problem? The error message is:
Cannot initialize a member subobject of type 'IRecognizer<Any, Any> *'
with an lvalue of type 'IRecognizer<Token *, ParserATNSimulator *> *'
The reason I use the Any class is to have a common type that could be assigned with any class reference (similar to Java's Object, but C++ has no common object type from which all other classes derive).
Maybe a different approach is possible here? I'm open for suggestions.
You are trying to convert a IRecognizer<T1, T2> * to a IRecognizer<Any, Any> *. The only allowed pointer conversion is from a derived class pointer to a base class pointer (i.e. Derived* to Base*) or to a more cv-qualified pointer to the same type (i.e. Derived* to Derived const*) or both.
IRecognizer<T1,T2> is not in the same class hierarchy as IRecognizer<Any, Any>. They are two unrelated types. You can add a constructor to convert an IRecognizer<A,B> to an IRecognizer<C,D> if that makes sense, but you can't add a similar thing for pointers.
A pointer to X is not the same as an X.
While you can convert an X into a Y (a IRecognizer<T1,T2> into an IRecognizer<Any,Any>), you cannot convert a pointer to X into a pointer to Y.
You may not want a pointer here. Instead, you might want a value.
However, an interface is not a value.
Java generics are not like C++ templates. A Java generic Bob<Type> is a wrapper around Bob<Object> -- it is actually storing an Object, with a bunch of wrapping casts to-and-from in a layer on top of it.
You can write such wrappers in C++. As an example:
class IRecognizer_base {
public:
virtual int getState() = 0;
};
template<typename Symbol, typename ATNInterpreter>
class IRecognizer:public IRecognizer_base {
};
Now, suppose getState() returned a Symbol:
class IRecognizer_base {
public:
virtual Any getState_() = 0;
};
template<typename Symbol, typename ATNInterpreter>
class IRecognizer:public IRecognizer_base {
public:
inline Symbol getState() {
return getState_(); // whatever conversion required to go from `Any` to `Symbol`
}
};
here, we expose the fact that our objects actually return an Any, but in the interface we cast them over.
If you actually exposed what operations are actually different based on the template types, you can do type erasing tactics that let you store anything that can do those operations instead of a pointer to a specific type.
I am trying to write a class that I can store and use type information in without the need for a template parameter.
I want to write something like this:
class Example
{
public:
template<typename T>
Example(T* ptr)
: ptr(ptr)
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(ptr == NULL)
return;
(*(EnclosedType*)ptr)(); // so i can cast the pointer and call the () operator if the class has one.
}
private:
void* ptr;
}
I am not asking how to write an is_functor() class.
I want to know how to get type information in a constructor and store it at the class level. If that is impossible, a different solution to this would be appreciated.
I consider this as a good and valid question, however, there is no general solution beside using a template parameter at the class level. What you tried to achieve in your question -- using a typedef inside a function and then access this in the whole class -- is not possible.
Type erasure
Only if you impose certain restrictions onto your constructor parameters, there are some alternatives. In this respect, here is an example of type erasure where the operator() of some given object is stored inside a std::function<void()> variable.
struct A
{
template<typename T>
A(T const& t) : f (std::bind(&T::operator(), t)) {}
void operator()() const
{
f();
}
std::function<void()> f;
};
struct B
{
void operator()() const
{
std::cout<<"hello"<<std::endl;
}
};
int main()
{
A(B{}).operator()(); //prints "hello"
}
DEMO
Note, however, the assumptions underlying this approach: one assumes that all passed objects have an operator of a given signature (here void operator()) which is stored inside a std::function<void()> (with respect to storing the member-function, see here).
Inheritance
In a sense, type erasure is thus like "inheriting without a base class" -- one could instead use a common base class for all constructor parameter classes with a virtual bracket operator, and then pass a base class pointer to your constructor.
struct A_parameter_base
{
void operator()() const = 0;
};
struct B : public A_parameter_base
{
void operator()() const { std::cout<<"hello"<<std::endl; }
};
struct A
{
A(std::shared_ptr<A_parameter_base> _p) : p(_p) {}
void operator()()
{
p->operator();
}
std::shared_ptr<A_parameter_base> p;
}
That is similar to the code in your question, only that it does not use a void-pointer but a pointer to a specific base class.
Both approaches, type erasure and inheritance, are similar in their applications, but type erasure might be more convenient as one gets rid of a common base class. However, the inheritance approach has the further advantage that you can restore the original object via multiple dispatch
This also shows the limitations of both approaches. If your operator would not be void but instead would return some unknown varying type, you cannot use the above approach but have to use templates. The inheritance parallel is: you cannot have a virtual function template.
The practical answer is to store either a copy of your class, or a std::ref wrapped pseudo-reference to your class, in a std::function<void()>.
std::function type erases things it stores down to 3 concepts: copy, destroy and invoke with a fixed signature. (also, cast-back-to-original-type and typeid, more obscurely)
What it does is it remembers, at construction, how to do these operations to the passed in type, and stores a copy in a way it can perform those operations on it, then forgets everything else about the type.
You cannot remember everything about a type this way. But almost any operation with a fixed signature, or which can be intermediaried via a fixed signature operation, can be type erased down to.
The first typical way to do this are to create a private pure interface with those operations, then create a template implementation (templated on the type passed to the ctor) that implements each operation for that particular type. The class that does the type erasure then stores a (smart) pointer to the private interface, and forwards its public operations to it.
A second typical way is to store a void*, or a buffer of char, and a set of pointers to functions that implement the operations. The pointers to functions can be either stored locally in the type erasing class, or stored in a helper struct that is created statically for each type erased, and a pointer to the helper struct is stored in the type erasing class. The first way to store the function pointers is like C-style object properties: the second is like a manual vtable.
In any case, the function pointers usually take one (or more) void* and know how to cast them back to the right type. They are created in the ctor that knows the type, either as instances of a template function, or as local stateless lambdas, or the same indirectly.
You could even do a hybrid of the two: static pimpl instance pointers taking a void* or whatever.
Often using std::function is enough, manually writing type erasure is hard to get right compared to using std::function.
Another version to the first two answers we have here - that's closer to your current code:
class A{
public:
virtual void operator()=0;
};
template<class T>
class B: public A{
public:
B(T*t):ptr(t){}
virtual void operator(){(*ptr)();}
T*ptr;
};
class Example
{
public:
template<typename T>
Example(T* ptr)
: a(new B<T>(ptr))
{
// typedef T EnclosedType; I want this be a avaialable at the class level.
}
void operator()()
{
if(!a)
return;
(*a)();
}
private:
std::unique_ptr<A> a;
}
I need to store multiple types of a template class in a single vector.
Eg, for:
template <typename T>
class templateClass{
bool someFunction();
};
I need one vector that will store all of:
templateClass<int> t1;
templateClass<char> t2;
templateClass<std::string> t3;
etc
As far as I know this is not possible, if it is could someone say how?
If it isn't possible could someone explain how to make the following work?
As a work around I tried to use a base, non template class and inherit the template class from it.
class templateInterface{
virtual bool someFunction() = 0;
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction();
};
I then created a vector to store the base "templateInterface" class:
std::vector<templateInterface> v;
templateClass<int> t;
v.push_back(t);
This produced the following error:
error: cannot allocate an object of abstract type 'templateInterface'
note: because the following virtual functions are pure within 'templateInterface'
note: virtual bool templateInterface::someFunction()
To fix this error I made the function in templateInterface not a pure virtual by providing a function body, this compiled but when calling the function the overide is not used, but instead the body in the virtual function.
Eg:
class templateInterface{
virtual bool someFunction() {return true;}
};
template <typename T>
class templateClass : public templateInterface{
bool someFunction() {return false;}
};
std::vector<templateInterface> v;
templateClass<int> i;
v.push_back(i);
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body
Is there any way to fix this so that the overridden function is used, or is there another workaround to store multiple template types in a single vector?
Why your code doesn't work:
Calling a virtual function on a value doesn't use polymorphism. It calls the function which is defined for the type of this exact symbol as seen by the compiler, not the runtime type. When you insert sub types into a vector of the base type, your values will be converted into the base type ("type slicing"), which is not what you want. Calling functions on them will now call the function as defined for the base type, since not it is of that type.
How to fix this?
The same problem can be reproduced with this code snippet:
templateInterface x = templateClass<int>(); // Type slicing takes place!
x.someFunction(); // -> templateInterface::someFunction() is called!
Polymorphism only works on a pointer or reference type. It will then use the runtime type of the object behind the pointer / reference to decide which implementation to call (by using it's vtable).
Converting pointers is totally "safe" with regard to type slicing. Your actual values won't be converted at all and polymorphism will work as expected.
Example, analogous to the code snippet above:
templateInterface *x = new templateClass<int>(); // No type slicing takes place
x->someFunction(); // -> templateClass<int>::someFunction() is called!
delete x; // Don't forget to destroy your objects.
What about vectors?
So you have to adopt these changes in your code. You can simply store pointers to actual types in the vector, instead of storing the values directly.
When working with pointers you also have to care about deleting your allocated objects. For this you can use smart pointers which care about deletion automatically. unique_ptr is one such smart pointer type. It deletes the pointee whenever it goes out of scope ("unique ownership" - the scope being the owner). Assuming the lifetime of your objects is bound to the scope this is what you should use:
std::vector<std::unique_ptr<templateInterface>> v;
templateClass<int> *i = new templateClass<int>(); // create new object
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector
v.emplace_back(new templateClass<int>()); // "direct" alternative
Then, call a virtual function on one of these elements with the following syntax:
v[0]->someFunction();
Make sure you make all functions virtual which should be possible to be overridden by subclasses. Otherwise their overridden version will not be called. But since you already introduced an "interface", I'm sure you are working with abstract functions.
Alternative approaches:
Alternative ways to do what you want is to use a variant type in the vector. There are some implementations of variant types, the Boost.Variant being a very popular one. This approach is especially nice if you don't have a type hierarchy (for example when you store primitive types). You would then use a vector type like std::vector<boost::variant<int, char, bool>>
Polymorphism only works through pointers or references. You'll
need the non-template base. Beyond that, you'll need to decide
where the actual objects in container will live. If they're all
static objects (with sufficient lifetime), just using
a std::vector<TemplateInterface*>, and inserting with
v.push_back(&t1);, etc., should do the trick. Otherwise,
you'll probably want to support cloning, and keep clones in the
vector: preferably with Boost pointer containers, but
std::shared_ptr can be used as well.
The solutions given so far are fine though be aware that in case you were returning the template type other than bool in your example , none of these would help as the vtable slots would not be able to be measured before hand. There are actually limits , from a design point of view , for using a template oriented polymorphic solution.
Solution nr. 1
This solution inspired by Sean Parent's C++ Seasoning talk. I highly recommend to check it out on youtube. My solution simplified a bit and the key is to store object in method itself.
One method only
Create a class that will invoke method of stored object.
struct object {
template <class T>
object(T t)
: someFunction([t = std::move(t)]() { return t.someFunction(); })
{ }
std::function<bool()> someFunction;
};
Then use it like this
std::vector<object> v;
// Add classes that has 'bool someFunction()' method
v.emplace_back(someClass());
v.emplace_back(someOtherClass());
// Test our vector
for (auto& x : v)
std::cout << x.someFunction() << std::endl;
Several methods
For several methods use shared pointer to share object between methods
struct object {
template <class T>
object(T&& t) {
auto ptr = std::make_shared<std::remove_reference_t<T>>(std::forward<T>(t));
someFunction = [ptr]() { return ptr->someFunction(); };
someOtherFunction = [ptr](int x) { ptr->someOtherFunction(x); };
}
std::function<bool()> someFunction;
std::function<void(int)> someOtherFunction;
};
Other types
Primitive types (such as int, float, const char*) or classes (std::string etc.) may be wrapped in the same way as object class do but behave differently. For example:
struct otherType {
template <class T>
otherType(T t)
: someFunction([t = std::move(t)]() {
// Return something different
return true;
})
{ }
std::function<bool()> someFunction;
};
So now it is possible to add types that does not have someFunction method.
v.emplace_back(otherType(17)); // Adding an int
v.emplace_back(otherType("test")); // A string
Solution nr. 2
After some thoughts what we basically done in first solution is created array of callable functions. So why not just do the following instead.
// Example class with method we want to put in array
struct myclass {
void draw() const {
std::cout << "myclass" << std::endl;
}
};
// All other type's behaviour
template <class T>
void draw(const T& x) {
std::cout << typeid(T).name() << ": " << x << std::endl;
}
int main()
{
myclass x;
int y = 17;
std::vector<std::function<void()>> v;
v.emplace_back(std::bind(&myclass::draw, &x));
v.emplace_back(std::bind(draw<int>, y));
for (auto& fn : v)
fn();
}
Conclusion
Solution nr. 1 is definitely an interesting method that does not require inheritance nor virtual functions. And can be used to other stuff where you need to store a template argument to be used later.
Solution nr. 2, on the other hand, is simpler, more flexible and probably a better choice here.
If you're looking at a container to store multiple types, then you should explore boost variant from the popular boost library.
Lets say I have a class Handler with some subclasses like stringhandler, SomeTypeHandler, AnotherTypeHandler. The class Handler defines a method "handle" as a common interface for all the subclasses. The logic to "handle" is ofcourse completely different for the different handlers.
So what I need to do is pass a value of anything to the handle method. The specific classes can then cast the "anything" to the type they expect.
Basically what I need is something like the java class Object :D
The first thing I tried was a void*, but apparently you can not do B* someB = dynamic_cast<B*>(theVoidPointer), so no luck there.
My second idea was to use boost::any. however, the requirement to use boost::any is that the value must be copy cunstructable, which is not the case for my data.
Any ideas to get this to work?
Thanks
EDIT: Note that I know I could use a SomeData class with no members at all, and let my data be subclasses of that, but I am looking for a more generic approach which does not require me to make my own wrapper class.
Okay, here is a simple approach using boost::any to hold pointers to your datatypes. However, beware that boost::any adds some overhead code decreasing performance slightly (in most cases neglectible).. consider using boost::spirit::hold_any instead, or void* if you don't need type safety.
class Handler {
public:
void handle( boost::any value ) {
do_handle( value );
}
private:
virtual void do_handle( boost::any& value ) = 0;
};
template<class T>
class HandlerBase : public Handler {
private:
void do_handle( boost::any& value ) {
// here you should check if value holds type T*...
handle_type( *(boost::any_cast<T*>( value )) );
}
void handle_type( const T& value ) = 0;
};
class StringHandler : HandlerBase<std::string> {
private:
void handle_type( const std::string& value ) {
// do stuff
}
};
Now you can write lots of handler classes, deriving from HandlerBase, without assuming that the handled types have a common base class.
You can for example define a base class:
class BaseHandlerData {
...
};
Then derive your specific data classes, which are expected by your handlers:
class StringData: public BaseHandlerData {
...
};
class SomeData: public BaseHandlerData {
...
};
Then you should be able to pass a BaseHandlerData* argument to the handle method, and use something like:
void handle(BaseHandlerData *data) {
StringData* stringData = dynamic_cast<StringData*>(...);
// handle your string data here ...
}
to safely cast to your expected data type.
Gerald
Another alternative, getting more toward the C world, would be a union type (http://en.wikipedia.org/wiki/Union_(computer_science)#C.2FC.2B.2B). This would only allow you to pass the types you specifiy, not any type, but has the type of behavior you describe.
You need to have a base class called DataObject or something. All of your data types, (string, number, whatnot) are sub classes of DataObject. The you define Handle like this:
void Handle(DataObject *dataObject);
This is a much safer way to do what you want. To make it even better, the DataObject can even know what kind of data it contains. Then the handlers can check that they've been sent the right type of data.
You can do
B* someB = static_cast<B*>(theVoidPointer);
Is there some way to allocate memory depending on the type of pointer passed?
Here is my problem: I have a 'bouncyball' and 'hero' class both inheriting from 'Actor'. To add a bouncyball, I call:
_actors.push_back(new Bouncyball());
For a hero, it would be:
_actors.push_back(new Hero());
Since _actors is a vector of Actor pointers, it works because of polymorphism. But I want to write a generic method to add new actors to my scene:
unsigned Scene::addActor(Actor * actor){
this->_actors.push_back(new [something]);
}
Because the parameter can be any derivative of Actor, I don't know what to allocate memory for... I can work around this with a case statement, but what if I derive other Actors later on?
What is wrong with this:
unsigned Scene::addActor(Actor * actor){
this->_actors.push_back(actor);
//what do you want to return? why not make return type as void?
}
Isn't it actor which you want to add to _actors?
And you can call addActor() as:
scene.addActor(new Bouncyball());
scene.addActor(new Hero());
Make sure that you declare the destructor of Actor as virtual, as most likely you would want to delete derived class objects through the pointer of base type (which is Actor).
Nawaz's solution is fine, but an alternative is a template member function:
template<typename T>
unsigned Scene::addActor()
{
_actors.push_back(new T());
}
And then in the client code:
scene.addActor<Hero>();
It's worth noting that the template member function will need to be implemented in a header or file included by a header (such as a .inl). If you implement it directly in the class body you shouldn't write Scene:: in front of addActor().
One advantage of this method is that clients are not calling new. It's generally 'bad' if code is calling new, but isn't calling delete, and in this case delete would presumably be called by the Scene class later. This also creates a pinch point if a custom allocator needs to be used for performance reasons.
Why not create a pv class Clonable:
template <typename T>
struct Clonable {
virtual smart_ptr<T> clone() const = 0;
}
for smart_ptr being std::shared_ptr, std::unique_ptr, boost::shared_ptr, etc.
The point is to refcount the pointer to avoid use of manual deletes, except when writing a custom Deleter.
Then define Actor as:
class Actor : ..., public Clonable<Actor> {
...
public:
...
virtual smart_ptr<T> clone() const { return 0; }
...
...
}
Then, for T : public Actor,
scene.addActor((T()).clone());