Pass base class to function delegate that recives the super class - c++

I have this map:
map<IEvent, EventHandler, IEventCompare>
Where EventHandler is defined as typedef void (*EventHandler)(IEvent);
IEvent is a class that describes a general event.
Now I want to add to this map a function that receives CreationEvent, a class that inherits IEvent. The function is defined so:
void onCreate(CreationEvent);
But when I try to add it to the map, I get a compilation error
E0167 argument of type "void (Engine::IObject::*)(Engine::CreationEvent)" is incompatible with parameter of type "Engine::EventHandler"
And if I try to explicitly convert it to EventHandler:
E0171 invalid type conversion
I can declare onCreate with IEvent, but I would like to avoid it since it will require me to assume the type of event, and it is not well defined.
Is there a way to do what I try?
IEvent:
/**
* Represents an Event, such as collision between 2 objects or click on an object.
*/
class IEvent
{
public:
IEvent(string name) { this->name = name; };
/**
* Copy constructor.
*/
IEvent(const IEvent& other) { this->name = other.name;};
string getName() const { return this->name; };
protected:
string name;
};
CreationEvent:
class CreationEvent : public IEvent
{
public:
CreationEvent();
std::chrono::time_point<std::chrono::system_clock> getCreateTime() const;
private:
std::chrono::time_point<std::chrono::system_clock> creationTime; /**< The creation time of this event.*/
};
Notes:
Everything is inside namespace Engine, and the map is declared inside IObject.

If I get your idea right, you want:
Have typed events with base event class.
Have handlers with base handler class.
Handlers can receive event of certain type.
Consider the next example. For the simplicity I used std::vector instead of std::map, and put it inside event class.
This code contains ugliness, leaks and must not be used in a "production" without modifications.
#include <iostream>
#include <vector>
//***********************************************************//
struct event;
struct handler
{
};
struct event_handler
{
event_handler(handler* receiver) : receiver_{ receiver } {}
handler* receiver_;
virtual void invoke(event& evt) = 0;
};
template <typename T, typename U>
struct event_handler_impl : event_handler
{
typedef void (T::* handler_function)(U&);
event_handler_impl(handler* receiver, handler_function function) :
event_handler{ receiver_ },
function_{ function } {}
void invoke(event& evt) {
T* typed_receiver = static_cast<T*>(receiver_);
U& typed_event = static_cast<U&>(evt);
(typed_receiver->*function_)(typed_event);
}
handler_function function_;
};
struct event
{
void subscribe(event_handler* hdlr)
{
//TODO: Check. Is double added?
handlers_.push_back(hdlr);
}
void sent()
{
for (auto& item : handlers_)
{
item->invoke(*this);
}
}
std::vector<event_handler*> handlers_;
};
//*****************************EXAMPLE***********************//
struct creation_event : public event
{
int creation_id{};
};
struct bar_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "bar" << evt.creation_id << std::endl;
}
};
struct foo_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "foo" << evt.creation_id << std::endl;
}
};
template<typename T, typename U>
void subscribe_to_event(U& evt, T* reciver, void (T::* handler_function)(U&))
{
evt.subscribe(new event_handler_impl<T, U>(reciver, handler_function));
}
int main()
{
creation_event evt;
bar_handler bar;
foo_handler foo;
subscribe_to_event(evt, &foo, &foo_handler::handle_creation);
subscribe_to_event(evt, &bar, &bar_handler::handle_creation);
evt.sent();
evt.creation_id = 1;
evt.sent();
return 0;
}
The only tricky part is:
template <typename T, typename U>
struct event_handler_impl : event_handler
Here we generating classes for storing our typed “callback” and using polymorphism to store those classes inside our std::vector since they are all child classes for handler.
As a suggestion - consider using smart pointers instead of raw pointers. Also you can put function void subscribe_to_even(…) to the handler base class, so you can remove second parameter and just pass "this" to the event_handler_impl - new event_handler_impl<T, U>(this, handler_function)

Related

C++ template class with dynamic callback function type

In the code below, I want a user to be able to create a consumer class with a specific type, eg Consumer<StateA> so their callback function can correctly handle the type they give it. However in the code below, the compiler complains because at compile time, the call to the function in the StateB consume method is not generated. The consume methods come from a base class and they have to be overriden.
template <class T>
class Consumer : ConsumerBase
{
public:
Consumer(std::function<void(T&)> _callback){
callback = _callback;
}
virtual void consume(StateA& state) {
callback(state);
}
virtual void consume(StateB& state) {
callback(state);
}
private:
std::function<void(T&)> callback;
};
Base Class:
class ConsumerBase
{
public:
virtual void consume(StateA& state) = 0;
virtual void consume(StateB& state) = 0;
};
How can I make this work?
The consume methods come from a base class and they have to be overriden. [...] How can I make this work?
I suppose that a possible solution is develop a couple of consume_h() ("consume helper") methods.
The first one is an exact match for T (the template type of the class) that call the callback function
void consume_h (T & state)
{ callback(state); }
The second one is a template version that do nothing
template <typename U>
void consume_h (U &)
{ }
Now you can override both virtual method calling consume_h()
virtual void consume (StateA & state)
{ consume_h(state); }
virtual void consume (StateB & state)
{ consume_h(state); }
This way the virtual method corresponding to T, call the consume_h() that call the callback; the other call the template consume_h() that do nothing.
The following is a full compiling example
#include <functional>
struct StateA { };
struct StateB { };
struct ConsumerBase
{
virtual void consume (StateA &) = 0;
virtual void consume (StateB &) = 0;
};
template <typename T>
class Consumer : ConsumerBase
{
public:
Consumer (std::function<void(T&)> cb0) : callback{cb0}
{ }
void consume_h (T & state)
{ callback(state); }
template <typename U>
void consume_h (U &)
{ }
virtual void consume (StateA & state)
{ consume_h(state); }
virtual void consume (StateB & state)
{ consume_h(state); }
private:
std::function<void(T&)> callback;
};
int main()
{
Consumer<StateA> csa{[](StateA &){ std::cout << "A" << std::endl; }};
Consumer<StateB> csb{[](StateB &){ std::cout << "B" << std::endl; }};
StateA sa;
StateB sb;
csa.consume(sa); // print A
csb.consume(sb); // print B
}

C++ Generic Event System

I am trying to build a generic event system. The Delegates and Events should not know anything about the other and a Manager will handle everything.
With this in mind I created a templated delegate/listener is made up of a function pointer and templated parameters.
class IDelegate
{
public:
IDelegate() {};
virtual ~IDelegate() = 0;
virtual void exec() = 0;
};
template<class Class, typename... Args>
class Delegate : public IDelegate
{
public:
typedef (Class::*Function)(Args);
Delegate(Class* inst, Function func) : instance(inst), function(func) {};
~Delegate() { instance = nullptr };
void exec(Args args)
{
instance->function(args);
}
private:
Class* instance;
Function function;
};
I did something similar on the Event side. The Events being made up of an ID and the Arguments that will need to be past to the function pointer.
class IEvent
{
public:
IEvent() {};
virtual ~IEvent() = 0;
};
template<typename... Args>
class Event : IEvent
{
public:
Event(ID eventID, Args args) : id(eventID), arguments(args) {};
~Event() = default;
ID id;
Args arguments;
};
I choose to use templates in the hope of not needing to manually create every event/delegate class that may be needed.
Lastly I wanted to make a Manager that would be a singleton.
//EventHandler.h
#pragma once
#include <string>
#include <unordered_map>
#include <queue>
#include "Event.h"
typedef std::string ID;
typedef std::unordered_multimap<ID, void*> Listeners;
class EventHandler
{
public:
EventHandler(const EventHandler& copy) = delete;
~EventHandler();
EventHandler& operator= (const EventHandler& rhs) = delete;
void Initialize();
template<class Class, class TEvent>
void Run();
void Shutdown();
static Listeners::iterator& Register(ID id, IDelegate* listener);
static void Deregister(Listeners::iterator& iterator);
static void Post(IEvent* evnt);
private:
static Listeners listeners;
static std::queue<IEvent*> events;
static EventHandler* instance;
EventHandler() {};
EventHandler(const EventHandler& copy);
EventHandler& operator= (const EventHandler& rhs);
};
//EventHandler.cpp
#include "EventHandler.h"
EventHandler::~EventHandler()
{
instance = nullptr;
}
void EventHandler::Initialize()
{
instance = this;
}
void EventHandler::Run()
{
//TODO: Determine the Event and cast or instantiate to the right class
IEvent* evnt = events.front; //This should not be IEvent*, but Event<>*
events.pop();
listeners[evnt->id].exec(evnt->arguments); //The delegate may need to be casted too.
}
void EventHandler::Shutdown()
{
instance = nullptr;
}
Listeners::iterator& EventHandler::Register(ID id, IDelegate* listener)
{
Listeners::iterator iter = listeners.emplace(id, listener);
return iter;
}
void EventHandler::Deregister(Listeners::iterator& iterator)
{
listeners.erase(iterator);
}
void EventHandler::Post(IEvent* evnt)
{
events.emplace(evnt);
}
Where I'm running into trouble is figuring out what Event I'm actually using in Run(). If possible I would like to do this without a switch or something similar as that would defeat the use of the templated classes. I have considered making the function pointer all be the same signature as this would simplify some of the code, but would make the system less flexible.
Thank you for any help.

c++ design: avoid iterating over types with an existing class hierarchy

Please consider the following (simplified) class hierarchy and processing functions:
struct msgBase
{
virtual int msgType() const=0;
};
struct msgType1:public msgBase
{
virtual int msgType() const{return 1;}
};
struct msgType2:public msgBase
{
virtual int msgType() const {return 2;}
};
void process(const msgType1& mt1)
{
// processing for message type 1
}
void process(const msgType2& mt2)
{
// processing for message type 2
}
void process(const msgBase& mbase)
{
switch(mbase.msgType())
{
case 1:
process(static_cast<const msgType1&>(mbase));
break;
case 2:
process(static_cast<const msgType2&>(mbase));
break;
}
}
In an integrated design, msgBase would be given a virtual "process" method, to avoid needing to iterate over the types.
If it's not possible or desirable to modify any of the classes, are there any alternatives to iterating over the types?
I've experimented with a decorator/factory pattern where a parallel hierarchy of classes encapsulates the given classes, and implements the necessary virtual functions, but this results in an awful lot of boilerplate, and the factory function still needs to iterate over the types!
I could replace the switch statement with a series of dyamic_casts, but that still leaves the same weaknesses.
As requested by Simon, here is what I mean by CRTP:
typedef <class Derived>
struct msgBase
{
virtual void process(){
// redirect the call to the derived class's process()
static_cast<Derived*>(this) -> process();
};
struct msgType1:public msgBase<msgType1>
{
void process(){
// process as per type-1
}
};
struct msgType2:public msgBase<msgType1>
{
void process(){
// process as per type-2
}
};
What's happening here? Consider this case:
msgBase* msg = new msgType1();
msg->process();
normally (without CRTP) this would only call msgBase::process(). But now, msgBase "knows" about msgType1 using the template, so it is redirected to msgType1::process at compile time.
Something like this could work:
These classes are used to do the casting automatically:
struct dispatcher_base {
virtual void process(const msgBase&) = 0;
};
template <class T>
struct dispatcher_impl : dispatcher_base {
void process(const msgBase& b) override {
::process(static_cast<const T&>(b));
}
};
We'll store them in a map:
auto g_table = std::map<int, std::unique_ptr<dispatcher_base>>{};
But now you have to initialize this table somewhere:
template <class T>
void register_msg() {
g_table[T{}.msgType()].reset(new dispatcher_impl<T>{});
}
...
register_msg<msgType1>();
register_msg<msgType2>();
You can add an assert to register_msg to make sure that msgTypes are unique.
Your process function will look like this:
void process(const msgBase& b) {
assert(g_table.find(b.msgType()) != g_table.end());
g_table[b.msgType()]->process(b);
}
You can replace assert with any other logic of course.
If you can't modify the classes then you can use decorators to get polymorphic type deduction.
struct DecorBase {
DecorBase(msgBase& b) : b_(b) {}
virtual ~DecorBase() {}
virtual void process() = 0;
msgBase& b_;
};
struct DecorType1 : public DecorBase {
DecorType1(msgType1& t1) : DecorBase(t1) {}
void process() override {
std::cout << "Processing Type 1" << std::endl;
}
};
struct DecorType2 : public DecorBase {
DecorType2(msgType2& t2) : DecorBase(t2) {}
void process() override {
std::cout << "Processing Type 2" << std::endl;
}
};
And use it like this:
msgType1 t1;
msgType2 t2;
DecorType1 dt1(t1); // Wrap objects in respective decorator.
DecorType2 dt2(t2);
DecorBase& base = dt2;
base.process(); // Uses polymorphism to call function in derived type.
This will require you to write a decorator for every derived type but at least you don't have to iterate over all types during the function call.

Make variable class member outside of constructor

Basically, I need to set a variable outside of the constructor and make it accessible to the entire class.
It would need to work something like this:
#include <iostream>
#include <string>
template <typename MT>
class CallbackFunction
{
void (*func)(MT);
MT *data;
public:
void SetCallbackData (void (*f)(MT), MT *d)
{
func = f;
data = d;
}
void Call()
{
func(data);
}
};
class Callback
{
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
// Need to make this a class member;
CallbackFunction <T> *CallbackClass = func;
}
void Call()
{
CallbackClass->Call();
}
};
template <typename CT>
Callback *NewCallback(void (*func)(CT), CT *data)
{
Callback *cb;
CallbackFunction <CT> *cf;
cf->SetCallbackData(func, data);
cb->SetCallback <CT> (cf);
return cb;
};
void Call(Callback *CallbackFunc)
{
CallbackFunc->Call();
}
void foo(std::string str)
{
std::cout << str << "\n";
}
int main()
{
std::string *str;
str->append("Hello, World!");
Call( NewCallback(foo, str) );
return 0;
}
More details:
I know it's buggy, and it doesn't compile, I'll sort out those bugs when I find a solution to my problem. Which is:
I need to find a way to declare a template variable inside a member function of the class "Callback". I need to do this because the class "Callback" cannot be a template, it needs to remain a simple class. So because the class "Callback" is not a template, I need to make one of it's member functions a template instead. So that member function can declare a variable of the type defined (with the template) when the function is called, and this variable needs to be accessible to the entire class.
So in a nice list:
class "Callback" cannot be a template,
variable CallbackClass must be accessible to the entire class,
but remain inside of the class.
#include <iostream>
#include <string>
#include <memory>
template <typename MT>
class CallbackFunction
{
typedef void (*func_ptr)(MT);
func_ptr f_ptr;
typedef std::shared_ptr<MT> data_ptr;
data_ptr data_p;
public:
void SetCallbackData (func_ptr f_ptr_, MT *d)
{
f_ptr = f_ptr_;
data_p.reset(d);
}
void Call()
{
if ( f_ptr ) f_ptr(data);
}
};
template<class T>
class Callback
{
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
f_ptr.reset(func);
}
void Call()
{
if ( f_ptr ) f_ptr->Call();
}
typedef std::shared_ptr<CallbackFunction<T>> func_ptr;
static func_ptr f_ptr;
};
I would implement this using polymorphism. Your programming skills seem good so I will just sketch the direction to solution, feel free to ask for more help if needed.
// your callbackobjects inherit from this class, the sole purpose of this
// class is to provide the Call interface. The derived classes implement
// their custom version of Call().
class CallBackObject{
public:
virtual void Call(){};
};
class Callback
{
CallBackObject *callBackObject;
public:
void SetCallback(CallBackObject *o)
{
callBackObject = o;
}
void Call()
{
callBackObject -> Call();
}
};
Create an abstract interface Callback class and have your CallbackFunction<T> inherit from this. Have your Callback class hold a pointer to this abstract interface. Finally, have your Callback::SetCallback assign func to this pointer.
Here's some code to illustrate the idea:
class ICallback
{
public:
virtual ~ICallback() {}
virtual void Call() = 0;
};
template <typename MT>
class CallbackFunction : public ICallback
{
typedef void (*callback)(MT);
callback myfunc;
MT *data;
public:
CallbackFunction (callback f, MT *d) :
myfunc (f),
data (d)
{}
void Call()
{
if(myfunc && data)
{
myfunc(*data);
}
else throw std::logic_error("Callback function or data is null!");
}
};
Then have Callback hold a ICallback*:
class Callback
{
ICallback *mycallback;
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
// Need to make this a class member;
// CallbackFunction <T> *CallbackClass = func;
mycallback = func;
}
void Call()
{
mycallback->Call();
}
};
The idea is to make all instantiated templates of CallbackFunction <T> a kind-of ICallback. Now the class using ICallback can take any class CallbackFunction <T> without needing to know what T is.

using RTTI in c++ to cast an object to the correct type

I'm trying to figure out a way to dynamically cast an instance of a child class to its parent in a somewhat difficult set of conditions.
Specifically, I have a an object hierarchy that looks something like (I've simplified a lot, so if something doesn't make sense, it might be due to the simplification):
class Object {
public:
virtual ~Object() {}
};
// shown just to give an idea of how Object is used
class IntObject: public Object {
protected:
int value;
public:
IntObject(int v) { value = v; }
int getValue() { return value; }
};
template <class T>
class ObjectProxy: public Object {
protected:
T *instance;
public:
ObjectProxy(T *instance): instance(instance) {}
T *getInstance() { return instance; }
};
The ObjectProxy class essentially acts as a wrapper to allow other types to be used in the Object hierarchy. Specifically, it allows pointers to class instances to be kept, and used later when invoking the instance's methods. For example, suppose I have:
class Parent {
protected:
int a;
public:
Parent(int v) { a = v; }
virtual ~Parent() {}
void setA(int v) { a = v; }
int getA() { return a; }
};
class Child: public Parent {
protected:
int b;
public:
Child(int v1, int v2): Parent(v1) { b = v2; }
void setA(int v) { b = v; }
int getB() { return b; }
};
I might use them in the following situation:
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxy<C> *proxy = dynamic_cast<ObjectProxy<C> *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
fn(proxy->getInstance());
}
void doSomething(Parent *parent) {
std::cout << "got: " << parent->getA() << std::endl;
}
int main() {
std::list<Object *> stack;
// this works
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Child>(stack, doSomething);
// this will fail (can't dynamically cast ObjectProxy<Child> to ObjectProxy<Parent>)
stack.push_back(new ObjectProxy<Child>(new Child(1, 2)));
callFn<Parent>(stack, doSomething);
}
As noted in the above comments, this code fails for a known reason. In the sample code, it's easy to avoid invoking callFn<Parent>(stack, doSomething). However, in my real code, I am using the signature of the function to determine type, and if its a method for the parent class, that will automatically be used for the template parameter.
My question is if there is any way to achieve the dynamic cast from ObjectProxy from an object of type of ObjectProxy. Part of the complication comes from the fact that in the function callFn, you only have the Parent type and not the child type.
I looked into using type-erasure via boost::any (i.e. ObjectProxy stops being templated, and instead has boost::any instance), but still ran into problems when it came to dynamic-casting (boost::any_cast is static). I did find mention to a dynamic_any on SO, but have not gotten it to work properly yet.
Any help or insight into the problem is greatly appreciated.
The dynamic cast is failing because the classes that are instantiations of ObjectProxy do not share the same hierarchy as the types given in the parameterisation of ObjectProxy. I see two approaches that may help. One, you make the types given to ObjectProxy share a single common base class and move the dynamic cast away from ObjectProxy and onto the instances.
namespace approach2 {
struct object_t {
virtual ~object_t() { }
};
struct required_base_t {
virtual ~required_base_t() { }
};
class object_proxy_base_t : public object_t {
required_base_t* instance_;
public:
object_proxy_base_t(required_base_t* i) : instance_ (i) { }
template <class T>
T* cast_to() const
{
return dynamic_cast<T*>(instance_);
}
};
template <class value_t>
class object_proxy_t : public object_proxy_base_t {
value_t* instance_;
public:
object_proxy_t(value_t* i)
: object_proxy_base_t (i),
instance_ (i)
{
}
};
template <class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_t<value_t>(new value_t(value));
}
struct parent_t : required_base_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy(parent_t());
object_t* b = new_with_proxy(child_t());
std::cout
<< dynamic_cast<object_proxy_base_t*>(a)->cast_to<parent_t>() << '\n' // works
<< dynamic_cast<object_proxy_base_t*>(b)->cast_to<parent_t>() << '\n' // works
;
}
}
This approach is not possible if you cannot change the base classes of all types used by ObjectProxy. Which leads to the second solution where you make ObjectProxy instantiations have the same hierarchy as the types used to parameterise it.
namespace approach3 {
struct object_t {
virtual ~object_t() { }
};
struct empty_t {
template <class T>
empty_t(T*) { }
};
template <class value_t>
class object_proxy_t : public virtual object_t {
value_t* instance_;
public:
object_proxy_t(value_t* i) : instance_ (i) { }
};
template <class value_t, class base_t>
class object_proxy_sub_t :
public object_proxy_t<value_t>,
public base_t {
public:
object_proxy_sub_t(value_t* i)
: object_proxy_t<value_t>(i),
base_t (i)
{
}
};
template <class base_t, class value_t>
object_t* new_with_proxy(value_t const& value)
{
return new object_proxy_sub_t<value_t, base_t>(new value_t(value));
}
struct parent_t {
virtual ~parent_t() { }
};
struct child_t : parent_t {
virtual ~child_t() { }
};
void f()
{
object_t* a = new_with_proxy<empty_t>(parent_t());
object_t* b = new_with_proxy<object_proxy_t<parent_t> >(child_t());
std::cout
<< dynamic_cast<object_proxy_t<parent_t>*>(a) << '\n' // works
<< dynamic_cast<object_proxy_t<parent_t>*>(b) << '\n' // works
;
}
}
This approach places fewer requirements on the types involved but means more work to keep the hierarchies in sync.
Building off of Bowie Owen's first answer, I realized that while the types given would likely not be derived from the same class (it's a library), I could force that to occur:
struct ObjectProxyBaseType {
virtual ~ObjectProxyBaseType() {}
};
template <class T>
class ObjectProxyType: public ObjectProxyBaseType, public T {
public:
// allow construction via parameters
template <typename... Args>
ObjectProxyType(Args &&... args): T(std::move(args)...) {}
// or construction via copy constructor
ObjectProxyType(T *t): T(*t) {}
virtual ~ObjectProxyType() {}
};
Thus, if I have class Child, I can create an instance of ObjectProxyType<Child>, which causes it to also inherit ObjectProxyBaseType. The rest of the code follows Bowie's suggestion:
class ObjectProxy: public Object {
protected:
ObjectProxyBaseType *instance;
public:
template <typename T>
ObjectProxy(ObjectProxyType<T> *i) {
instance = i;
}
template <typename T>
ObjectProxy(T *value) {
instance = new ObjectProxyType<T>(value);
}
template <typename T>
T *castTo() const {
return dynamic_cast<T *>(instance);
}
};
And an example of code that works:
int main() {
std::list<Object *> stack;
stack.push_back(new ObjectProxy(new Child(1, 2)));
callFn<Child>(stack, doSomething);
stack.push_back(new ObjectProxy(new Child(5, 6)));
callFn<Parent>(stack, doSomething);
}
I've had to do something somewhat similar recently. I've used an approach which worked for me, but might not be appropriate in this case; use your discretion. This hinges on the fact that you (or the person extending this code, if any) have full knowledge of what hierarchies will be used as template parameters.
So let's say these hierarchies are the following:
class Parent1
class Child1: public Parent1
class Child11: public Child1
...
class Parent2
class Child2: public Parent2
...
Then you build a holder class. It is a bit complicated for a simple reason - my compiler doesn't support default template parameters on functions, so I am using helper structs to enable SFINAE.
This class needs to be able to hold objects belonging to all hierarchies (through a base class pointer).
class TypeHolder
{
template<class T, class E=void>
struct GetHelper
{
static T* Get(const TypeHolder* th) { return nullptr; }
//you can actually add code here to deal with non-polymorphic types through this class as well, if desirable
};
template<class T>
struct GetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static T* Get(const TypeHolder* th)
{
switch(th->type)
{
case P1: return dynamic_cast<T*>(th->data.p1);
case P2: return dynamic_cast<T*>(th->data.p2);
//and so on...
default: return nullptr;
}
}
};
template<class T, class E=void>
struct SetHelper
{
static void Set(T*, TypeHolder* th) { th->type = EMPTY; }
};
template<class T>
struct SetHelper<T, typename std::enable_if<std::is_polymorphic<T>::value, void>::type>
{
static void Set(T* t, TypeHolder* th)
{
th->data.p1 = dynamic_cast<Parent1*>(t);
if(th->data.p1) { th->type = P1; return; }
th->data.p2 = dynamic_cast<Parent2*>(t);
if(th->data.p2) { th->type = P2; return; }
//...and so on
th->type = EMPTY;
}
};
public:
TypeHolder(): type(EMPTY) { }
template<class T>
T* GetInstance() const
{
return GetHelper<T>::Get(this);
}
template<class T>
void SetInstance(T* t)
{
SetHelper<T>::Set(t, this);
}
private:
union
{
Parent1* p1;
Parent2* p2;
//...and so on
} data;
enum
{
EMPTY,
P1,
P2
//...and so on
} type;
};
By the way, the reason we need the SFINAE trick is because of the dynamic_casts, which will not compile on non-polymorphic types.
Now all you need to do is modify your classes just a little bit :)
class ObjectProxyBase
{
public:
virtual const TypeHolder& GetTypeHolder() const = 0;
};
template<class T>
class ObjectProxy: public Object, public ObjectProxyBase
{
T* instance;
static TypeHolder th; //or you can store this somewhere else, or make it a normal (but probably mutable) member
public:
ObjectProxy(T* t): instance(t) { }
T* getInstance() const { return instance; }
const TypeHolder& GetTypeHolder() const { th.SetInstance(instance); return th; }
//... and the rest of the class
};
template<class T>
TypeHolder ObjectProxy<T>::th;
I hope this code is actually correct, since I mostly typed it into the browser window (mine used different names).
And now for the final piece: the function.
template <typename C>
void callFn(std::list<Object *> &stack, std::function<void (C*)> fn) {
Object *value = stack.front();
stack.pop_front();
ObjectProxyBase *proxy = dynamic_cast<ObjectProxyBase *>(value);
if (proxy == nullptr) {
throw std::runtime_error("dynamic cast failed");
}
C* heldobj = proxy->GetTypeHolder().GetInstance<C>(); //I used to have a dynamic_cast here but it was unnecessary
if (heldobj == nullptr) {
throw std::runtime_error("object type mismatch");
}
fn(heldobj);
}
You only need to use this approach for hierarchies, and can still use the dynamic_cast directly to ObjectProxy<C>* in other cases (essentially, you'll want to try both and see if one succeeds).
I hope this is at least a little bit helpful.