EDIT, CLARIFICATION:
*I want to be able to set eventHandlers using my own class EventListener using an overloaded operator >> and I can’t figure out the syntax for it*
The problem is that the overloaded >>= operator will not match a parameterized eventHandler, I do not know how to declare it properly!!
OR
If I make it match, the information required to convert the generic T type to a decent useful eventHandler object is gone!! I need a mixed syntax for declarind a generic type T and a second generic type as it parameter .
And using the parent of eventHandler class, the efunctor is also useless as it is not parameterized.
Example:
Link >> new eventHandler(&App::testFunction, app); /*where app is an istance of App class and testFunction is a method of App. */
I have a class called eventHandler that goes under this form eventHandler<class T>. Now, I want to overload the >> operator of some class to allow me to use it like this:
link >> new eventHandler(&App::testFunction, App);
Where App is another class, and testFunction is, obviously, a method of that class. The line written abose should have as an effect a call to the >>= operator of the link’s class (called, conveniently,Link).
I will post part of my code to make it more clearly:
class Link
{
public:
eventListener* EventListener;
Link()
{
this->EventListener = new eventListener();
}
// PROBLEM
// I am lost here, tried different syntaxes but with no success
//template<template<class G> class T, class F>
template <class T>
Link operator>>=(T& ev)
{
cout << "something";
// Here there is no way to declare the proper eventHandler
eventHandler<?>* event = (eventHandler<?>)ev;
// I need something like T<F>
event->eventName = 'onTest';
this->eventListener->add(event);
return *this;
}
};
template<class T, class F>
T operator>>(T& lhs, F& rhs)
{
return T(lhs)>>=rhs;
}
class App
{
public:
void testFunction(e evt)
{
cout << "it works!" << "\n";
}
};
int main()
{
App* app = new App;
Link* link = new link;
Link link1;
eventHandler<App>* ev = new eventHandler<App>(app, &App::testFunction);
link1 >> ev;
// this line should echo "it works!"
link1.EventListener->triggerEvent("onTest");
// PART 2
// HOW CAN I USE?
// link >> ev;
// when link is a Link*
return 0;
}
MY question is about how to declare the method operator>>= from Link so that automatically will enable me that kind of functionality.
Clarifications:
– I want to be able to add to the EventListener class a new eventHandler using the >> operator on the Link class having as right hand operand an actual eventHandler;
EDIT 1:
And I have a second question:
How to declare the >> overloaded function so that I will be called with pointer to the Link class… meaning what can I do if I want to use link with >> instead of link1.
Answer to PART2: My guess is that I just have to dereference the pointer in order to use the operator overloading.
ANOTHER EDIT
This is a version of the code that might explain it a little better. My problem is where the compiler fails, at matching >>= operator inside Link class, from there if that is solved properly it might work, the problem is that I cannot find how to match it and keep the event signature.
And now, I better let the code speak for itself:
#include <iostream>
#include <stdio.h>
#include "events/events.h"
using namespace std;
class Link
{
public:
eventListener* EventListener;
public:
Link()
{
this->EventListener = new eventListener();
}
template<class T>
Link operator>>=(const T& ev)
{
ev->eventName = "onReceive";
this->EventListener->add(ev);
return *this;
}
};
template<class T, class F>
T operator>>(T& lhs, const F& rhs)
{
return T(lhs)<<=rhs;
}
class App
{
public:
void testReceive(e evt)
{
cout << "it works" << "\n" << evt.value;
}
};
class demo
{
public:
Link* parent;
void testit(char* msg)
{
parent->EventListener->triggerEvent("onReceive", this, msg);
}
};
int main()
{
App* app = new App;
Link link;
eventHandler<App>* ev = new eventHandler<App>(app, &App::testReceive);
link >> ev;
demo d;
d.parent = &link;
// should output "it works!"
d.testit("here");
return 0;
}
I will also post my events definitions:
#ifndef EVENTS_H
#define EVENTS_H
#include <stdio.h>
#include <string.h>
#include "clist.h"
#include <string>
enum scope {global = 0, scoped};
struct e
{
void* target;
void* value;
};
class efunctor //abstract
{
public:
std::string eventname;
virtual void operator()(e evt)
{ }
virtual void Call(e evt)
{ }
};
template <class T>
class eventHandler : public efunctor
{
private:
T* scope;
void (T::*eventMethod)(e);
public:
std::string name;
std::string eventname;
eventHandler(std::string eventnam, T* objscope, void(T::*func)(e))
{
this->scope = objscope;
this->eventMethod = func;
this->eventname = eventnam;
}
eventHandler(T* objscope, void(T::*func)(e))
{
this->scope = objscope;
this->eventMethod = func;
}
eventHandler(void(T::*func)(e))
{
this->eventMethod = func;
}
void operator()(e evt)
{
(scope->*eventMethod)(evt);
}
void Call(e evt)
{
(scope->*eventMethod)(evt);
}
};
class eventListener
{
private:
clist< clist<efunctor* > > methods;
public:
template <class T>
void add(T other)
{
other->name = ToString(this->methods[other->eventname].length());
methods[other->eventname][methods[other->eventname].length()] = other;
}
template <class T>
void remove(T other)
{
methods[other->eventname]->remove(other->name);
}
template <class F>
void triggerEvent(std::string name, void* target, F result)
{
e evt;
evt.target = target;
evt.value = (char*)result;
for(methods[name].iterateStart();
!methods[name].eoi();
methods[name].next())
{
(*(methods[name].getCurrentIteration()))(evt);
}
}
};
#endif
Apart from the excessive use of
newthere are other things which I think you need to get conceptually clear before trying something like this. There isn’t really any problem in overloadingoperator>>()to call a suitable member version ofoperator>>=()if necessary although it might not even necessary to do this: if you control the left hand argument of your shift operator, you can make this a member if you want to. It just doesn’t work withstd::istreamthis way because you can’t control the standard C++ library class [template].Before going any further, let’s answer the question you added first: you cannot overload any operator which involves only built-in types. Pointers are considered built-in types. End of story. You should be using pointers anyway: they are a low-level abstraction you need in some place but on a higher level you want to deal with objects of appropriate classes. This doesn’t make things harder in any way but it makes things easier.
In your code all of a sudden some template template shows up: this is almost certainly not necessary and rather part of your problem. Also, if you want your events receiver to be in some sort polymorphic, you will need a small inheritance hierarchy somewhere: you would define a base class which exposes the interface use to trigger an event and a templated derived class which implements the few virtual functions defined by this interface. When an event is invoked the base just calls the virtual function and the even receives it. This is how
std::function<Signature>effectively works.I think there are too many undefined things in your question to answer it with a code example which effectively implements what you want. Personally, I would follow the model of
std::function<>and define an event template which take the signatures of events to be triggered as argument and function object with the corresponding signature as receivers. That is, the event you subscribe to looks like this:If you want to add an object with a specific member to be called on it you would do something and this is a common use case, you can create an
EventHandlerclass template to be used with this which effectively does something along the lines of(this just uses
std::bind()for brevity; if you want to support function with a fixed number of arguments this is easily implemented, assuming you cannot usestd::bind()orboost::bind()although you don’t want to reimplementbind(): this is a fairly hairy thing to do).Here is a complete and working example which I think shows all the ingredients (and gets as close as what I think you actually want as possible):
Note, that there are obvious extensions like making the argument type a template argument. This amounts to just adding this template argument in various places but the overall approach stays the same.