How to add/design callback function - c++

How do I setup/register a callback function, in C++, to call a function when there is data to be read from a queue?
Edit 1:
Using Neil's answer for a complete answer (in header file):
#include <vector.h>
class QueueListener {
public:
virtual void DataReady(class MyQueue *q) = 0;
virtual ~QueueListener() {}
};
class MyQueue {
public:
void Add (int x) {
theQueue.push_back(x);
for (int i = 0; i < theCallBacks.size(); i++) {
theCallBacks[i]->DataReady(this);
}
}
void Register (QueueListener *ql) {
theCallBacks.push_back(ql);
}
private:
vector <QueueListener *> theCallBacks;
vector <int> theQueue;
};
class MyListener : public QueueListener {
public:
virtual ~MyListener () {
printf("MyListener destructor!");
}
MyListener(MyQueue *q);
virtual void DataReady(class MyQueue *p);
};
And the registering:
#include "File1.h"
MyListener::MyListener(MyQueue *q)
{
q->Register(this);
}
void MyListener::DataReady(class MyQueue *p)
{
Sleep(500);
}
Then the calls:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MyQueue *q = new MyQueue();
MyListener ml(q);
q->Add(1);
}

In outline, create a QueueListener base class:
class QueueListener {
public:
virtual void DataReady( class MyQueue & q ) = 0;
virtual ~QueueListener() {}
};
and a queue class (make this queue of integers as example:
class MyQueue {
public:
void Add( int x ) {
theQueue.push_back( x );
for ( int i = 0; i < theCallBacks.size(); i++ ) {
theCallBacks[i]->DataReady( * this );
}
}
void Register( QueueListener * ql ) {
theCallBacks.push_back( ql );
}
private:
vector <QueueListener *> theCallBacks;
SomeQueueType <int> theQueue;
};
You derive the classes that want to be called back from QueueListener and implement the DataReady function. You then register instances of the derived class with your queue instance.

Have a look at Boost.Signals.
Example stolen from tutorial:
struct HelloWorld
{
void operator()() const
{
std::cout << "Hello, World!" << std::endl;
}
};
// ...
// Signal with no arguments and a void return value
boost::signal<void ()> sig;
// Connect a HelloWorld slot
HelloWorld hello;
sig.connect(hello);
// Call all of the slots
sig();

I like the approach that boost.asio uses for callback. In ASIO they are referred to as handlers. Please excuse my c++0x, it is so much faster to write than c++98.
class MyQueue
{
//...
Register( const std::function<void()>& callback )
{
m_callbacks.push_back(callback);
}
Add( const int& i )
{
// ...
for( const auto& callback: m_callbacks )
{
callback();
}
}
std::vector<std::function<void()>> m_callbacks;
};
class SomeClass
{
public:
void SomeQueueIsReady( MyQueue& )
{ /* do something with MyQueue */ }
};
void register_callback()
{
SomeClass some;
MyQueue queue;
// using bind
queue.Register( std::bind( &SomeClass::SomeQueueIsReady, &some, std::ref(queue) ) );
// or using a lambda
queue.Register( [&queue,&some](){ some.SomeQueueIsReady( queue ); } );
}
The key points are the callback is a functor so the user isn't tied to a particular class hierarchy and the callbacks don't take any parameters. If you want parameters passed in, you bind them yourself. The exception is if the callback produces information not available when the callback was registered. An example could be the time when the item was added.
There is nothing stopping you from using this solution in c++98. You cannot use lamdbas, but boost::function and boost::bind are near identical to their c++0x counter parts.
Be aware that you'll have to manage object lifetimes carefully. That is the case with either Neil's or my solution.

Related

I want to use abstract classes from C++, but why do I get a segfault?

My purpose is to register the Hanlder object in the KibanaManager. When the KibanaManager obtains the log from the kibana server regularly, it will hand over the log to the Hanlder object in the queue for processing.
For example, if the Handler finds the ERROR log, it will call the showMessage function of Qt's SystemTrayIcon. A message popup appears in the lower right corner.
code show as below:
kibana.h:
namespace favour {
enum KIBANA_LOG_LEVEL {
...
};
struct KibanaLog {
...
};
class KEHandler {
public:
virtual void handler(KibanaLog *kl) {};
};
class KibanaManager {
private:
static std::vector<KEHandler *> HANDLERS;
public:
static void init();
static void registerHandler(KEHandler *handler);
private:
static void polling(void *message);
};
}
#endif
kibana.cpp:
using namespace std;
namespace favour {
vector<KEHandler *> KibanaManager::HANDLERS = vector<KEHandler *>();
void KibanaManager::init() {
pthread_t threadId;
int code = pthread_create(&threadId, nullptr, (void *(*)(void *)) &polling, nullptr);
if (code) {
errno = code;
string message = "Kibana Manager init failed.";
message.append(strerror(errno));
throw runtime_error(message);
}
}
void KibanaManager::registerHandler(KEHandler *handler) {
for (auto item : HANDLERS) {
if (item == handler) return;
}
HANDLERS.push_back(handler);
}
void KibanaManager::polling(void *message) {
while (1) {
sleep(1);
for (auto h : HANDLERS) {
KibanaLog log;
h->handler(&log);
}
}
}
}
KibanaManagerTest.cpp:
namespace favour {
class DemoHandler : public KEHandler {
public:
void handler(KibanaLog *log) override {
std::cout << "Hello World" << std::endl;
}
};
void KibanaManagerTest::registerHandlerTest() {
KibanaManager::init();
DemoHandler *handler = new DemoHandler;
KibanaManager::registerHandler(handler);
delete handler;
while (1) {};
}
}
The program did not run as I expected, but when calling the handler function inherited from KEHandler and overridden by DemoHandler, a bit segmentation fault occurred, which caused the program to crash.

C++ object for callback with variable parameters list

I am writing callbacks system. I would to have something like that:
void someFunction(int, int);
void otherFunction(int, bool, std::string);
CallbackFunc *callback1 = new CallbackFunc( someFunction );
CallbackFunc *callback2 = new CallbackFunc( otherFunction );
callback1-> call(2, 6);
callback1-> call(1024, 456);
callback2-> call(-33, true, "Hello world");
My classes should can call each given function: don't know parameters count and their types.
I was trying that:
class Callback {
public:
virtual void call(...) = 0;
};
class CallbackFunc: public Callback {
protected:
void (*m_proc)(...);
public:
CallbackFunc(void (*proc) (...)) {
this-> m_proc = proc;
}
void call (...) {
this-> m_proc(<arguments given to call>);
}
};
But it doesn't work. I have second idea:
template<typename ArgType>
class Arg {
protected:
ArgType va;
public:
Arg() {
}
Arg(ArgType v) {
this->va = v;
}
ArgType get() {
return this->va;
}
void operator =(ArgType v) {
this->va = v;
}
};
class Callback {
public:
virtual void call(Arg, ...) = 0;
};
class CallbackFunc: public Callback {
protected:
void (*m_proc)(Arg ...);
public:
CallbackFunc(void (*proc) (Arg ...)) {
this-> m_proc = proc;
}
void call (Arg arg...) {
va_list args;
va_start(args, arg);
this-> m_proc(args);
va_end(args);
}
};
Still errors. Is it possible to make this way? I want to make usable code - user shouldn't know if CallbackFunc uses templates. I can't use void* and boost. C++ 2011 is not supported completely by some compilers I use, so that I can't use this standard too.

Need some way to store functions in a list, and then call them

This list, has to hold functions, they might be from different namespaces and even methods of instanced classes.
This list will then be iterated and all the functions and methods called. It would be nice if they could contain arguments also.
I was thinking on using a std::vector, but I suspect that I am far from correct in that guess.
What approach do you recommend me? All help is welcome.
You could use std::function and std::bind if your compiler already supports it.
#include <functional>
#include <vector>
void x(int) {}
void y() {}
class Z {
public:
void z() {}
};
int main(int argc, char *argv[])
{
typedef std::function<void ()> VoidFunc;
typedef std::vector<VoidFunc> FuncVector;
FuncVector functions;
functions.push_back(std::bind(&x, 1));
functions.push_back(&y);
Z z1;
functions.push_back(std::bind(&Z::z, z1));
for(FuncVector::iterator i = functions.begin(); i != functions.end(); i++) {
(*i)();
}
return 0;
}
Have all of your functions implement the Command Pattern.
Your list becomes a
std::list<Command>
As you iterate over the list, you invoke the Execute() method of each list item.
For example, say you have a simple Command interface called Commander:
class Commander
{
public:
virtual ~Commander;
virtual void Execute();//= 0;
};
And you have three objects that you want to put in your list: A Greyhound, a Gyrefalcon, and a Girlfriend. Wrap each in a Commander object that calls the object's function of interest. The Greyhound runs:
class RunGreyhound: public Commander
{
public:
void Execute()
{
mGreyhound->Run();
}
private:
Greyhound* mGreyhound;
};
The Gyrefalcon flies:
class RunGyrefalcon: public Commander
{
public:
void Execute()
{
mGyrefalcon->Fly( mGyrefalcon->Prey() );
}
private:
Gyrefalcon* mGyrefalcon;
};
And the Girlfriend squawks:
class RunGirlfriend: public Commander
{
public:
void Execute()
{
mGirlfriend->Squawk( mGirlfriend->MyJunk(), mGirlfriend->Mytrun() );
}
private:
Girlfriend* mGirlfriend;
};
Stuff the Commander objects in your list. Now you can iterate over them and invoke each element's Execute() method:
std::list<Commander> cmdlist;
RunGreyhound dog;
cmdlist.push_back( dog );
RunGyrefalcon bird;
cmdlist.push_back( bird );
RunGirlfriend gurl;
cmdlist.push_back( gurl );
for ( std::list<Commander>::iterator rit = cmdlist.begin(); rit != cmdlist.end(); ++rit )
{
rit->Execute();
}
If you don't want to use an existing solution such as boost::function, you will need to create a base class that represents a function, and then derived classes that wrap various sources of functions. For example:
#include <iostream>
#include <list>
using std::cout;
using std::list;
struct Function {
virtual ~Function() { }
virtual void operator()() = 0;
};
struct PlainFunction : Function {
PlainFunction(void (*function_ptr_arg)()) : function_ptr(function_ptr_arg) { }
virtual void operator()() { (*function_ptr)(); }
void (*function_ptr)();
};
template <typename T>
struct MethodFunction : Function {
MethodFunction(T &obj_arg,void (T::*method_ptr_arg)())
: obj(obj_arg), method_ptr(method_ptr_arg)
{
}
virtual void operator()() { (obj.*method_ptr)(); }
T &obj;
void (T::*method_ptr)();
};
void f()
{
cout << "Called f()\n";
}
struct A {
void f() { cout << "Called A::f()\n"; }
};
int main(int argc,char **argv)
{
list<Function *> functions;
functions.push_back(new PlainFunction(f));
A a;
functions.push_back(new MethodFunction<A>(a,&A::f));
list<Function *>::iterator i = functions.begin();
for (;i!=functions.end();++i) {
(*(*i))();
}
while (!functions.empty()) {
Function *last_ptr = functions.back();
functions.pop_back();
delete last_ptr;
}
}

Callback in C++, template member?

Following code does NOT work, but it expresses well what I wish to do. There is a problem with the template struct container, which I think SHOULD work because it's size is known for any template argument.
class callback {
public:
// constructs a callback to a method in the context of a given object
template<class C>
callback(C& object, void (C::*method)())
: ptr.o(object), ptr.m(method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
template<class C>
struct {
C& o;
void (C::*m)();
} ptr;
};
Is there any way to do such a thing? I mean have a non-template class callback which wraps any pointer to method?
Thanks C++ gurus!
Edit:
Please see this:
Callback in C++, template member? (2)
This is a complete working example that does what I think you're trying to do:
#include <iostream>
#include <memory>
// INTERNAL CLASSES
class CallbackSpecBase
{
public:
virtual ~CallbackSpecBase() {}
virtual void operator()() const = 0;
};
template<class C>
class CallbackSpec : public CallbackSpecBase
{
public:
CallbackSpec(C& o, void (C::*m)()) : obj(o), method(m) {}
void operator()() const { (&obj->*method)(); }
private:
C& obj;
void (C::*method)();
};
// PUBLIC API
class Callback
{
public:
Callback() {}
void operator()() { (*spec)(); }
template<class C>
void set(C& o, void (C::*m)()) { spec.reset(new CallbackSpec<C>(o, m)); }
private:
std::auto_ptr<CallbackSpecBase> spec;
};
// TEST CODE
class Test
{
public:
void foo() { std::cout << "Working" << std::endl; }
void bar() { std::cout << "Like a charm" << std::endl; }
};
int main()
{
Test t;
Callback c;
c.set(t, &Test::foo);
c();
c.set(t, &Test::bar);
c();
}
I recently implemented this:
#define UNKOWN_ITEM 0xFFFFFFFF
template <typename TArg>
class DelegateI
{
public:
virtual void operator()(TArg& a)=0;
virtual bool equals(DelegateI<TArg>* d)=0;
};
template <class TArg>
class Event
{
public:
Event()
{
}
~Event()
{
for (size_t x=0; x<m_vDelegates.size(); x++)
delete m_vDelegates[x];
}
void operator()(TArg& a)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
m_vDelegates[x]->operator()(a);
}
}
void operator+=(DelegateI<TArg>* d)
{
if (findInfo(d) != UNKOWN_ITEM)
{
delete d;
return;
}
m_vDelegates.push_back(d);
}
void operator-=(DelegateI<TArg>* d)
{
uint32 index = findInfo(d);
delete d;
if (index == UNKOWN_ITEM)
return;
m_vDelegates.erase(m_vDelegates.begin()+index);
}
protected:
int findInfo(DelegateI<TArg>* d)
{
for (size_t x=0; x<m_vDelegates.size(); x++)
{
if (m_vDelegates[x]->equals(d))
return (int)x;
}
return UNKOWN_ITEM;
}
private:
std::vector<DelegateI<TArg>*> m_vDelegates;
};
template <class TObj, typename TArg>
class ObjDelegate : public DelegateI<TArg>
{
public:
typedef void (TObj::*TFunct)(TArg&);
ObjDelegate(TObj* t, TFunct f)
{
m_pObj = t;
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
ObjDelegate<TObj,TArg> *d = dynamic_cast<ObjDelegate<TObj,TArg>*>(di);
if (!d)
return false;
return ((m_pObj == d->m_pObj) && (m_pFunct == d->m_pFunct));
}
virtual void operator()(TArg& a)
{
if (m_pObj && m_pFunct)
{
(*m_pObj.*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
TObj* m_pObj; // pointer to object
};
template <typename TArg>
class FunctDelegate : public DelegateI<TArg>
{
public:
typedef void (*TFunct)(TArg&);
FunctDelegate(TFunct f)
{
m_pFunct = f;
}
virtual bool equals(DelegateI<TArg>* di)
{
FunctDelegate<TArg> *d = dynamic_cast<FunctDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pFunct == d->m_pFunct);
}
virtual void operator()(TArg& a)
{
if (m_pFunct)
{
(*m_pFunct)(a);
}
}
TFunct m_pFunct; // pointer to member function
};
template <typename TArg>
class ProxieDelegate : public DelegateI<TArg>
{
public:
ProxieDelegate(Event<TArg>* e)
{
m_pEvent = e;
}
virtual bool equals(DelegateI<TArg>* di)
{
ProxieDelegate<TArg> *d = dynamic_cast<ProxieDelegate<TArg>*>(di);
if (!d)
return false;
return (m_pEvent == d->m_pEvent);
}
virtual void operator()(TArg& a)
{
if (m_pEvent)
{
(*m_pEvent)(a);
}
}
Event<TArg>* m_pEvent; // pointer to member function
};
template <class TObj, class TArg>
DelegateI<TArg>* delegate(TObj* pObj, void (TObj::*NotifyMethod)(TArg&))
{
return new ObjDelegate<TObj, TArg>(pObj, NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(void (*NotifyMethod)(TArg&))
{
return new FunctDelegate<TArg>(NotifyMethod);
}
template <class TArg>
DelegateI<TArg>* delegate(Event<TArg>* e)
{
return new ProxieDelegate<TArg>(e);
}
use it like so:
define:
Event<SomeClass> someEvent;
enlist callbacks:
someEvent += delegate(&someFunction);
someEvent += delegate(classPtr, &class::classFunction);
someEvent += delegate(&someOtherEvent);
trigger:
someEvent(someClassObj);
You can also make your own delegates and overide what they do. I made a couple of others with one being able to make sure the event triggers the function in the gui thread instead of the thread it was called.
You need to use polymorphism. Use an abstract base class with a virtual invocation method (operator() if you please), with a templated descendant that implements the virtual method using the correct type signature.
The way you have it now, the data holding the type is templated, but the code meant to invoke the method and pass the object isn't. That won't work; the template type parameters need to flow through both construction and invocation.
#Barry Kelly
#include <iostream>
class callback {
public:
virtual void operator()() {};
};
template<class C>
class callback_specialization : public callback {
public:
callback_specialization(C& object, void (C::*method)())
: o(object), m(method) {}
void operator()() {
(&o ->* m) ();
}
private:
C& o;
void (C::*m)();
};
class X {
public:
void y() { std::cout << "ok\n"; }
};
int main() {
X x;
callback c(callback_specialization<X>(x, &X::y));
c();
return 0;
}
I tried this, but it does not work (print "ok")... why?
Edit:
As Neil Butterworth mentioned, polymorphism works through pointers and references,
X x;
callback& c = callback_specialization<X>(x, &X::y);
c();
Edit:
With this code, I get an error:
invalid initialization of non-const reference of type ‘callback&’
from a temporary of type ‘callback_specialization<X>’
Now, I don't understand that error, but if I replace callback& c with const callback& c and virtual void operator()() with virtual void operator()() const, it works.
You didn't say what errors you found, but I found that this worked:
template<typename C>
class callback {
public:
// constructs a callback to a method in the context of a given object
callback(C& object, void (C::*method)())
: ptr(object,method) {}
// calls the method
void operator()() {
(&ptr.o ->* ptr.m) ();
}
private:
// container for the pointer to method
// template<class C>
struct Ptr{
Ptr(C& object, void (C::*method)()): o(object), m(method) {}
C& o;
void (C::*m)();
} ptr;
};
Note that Ptr needs a constructor as it has a reference member.
You could do without struct Ptr and have the raw members.
Tested with VS2008 express.
Improving the OP's answer:
int main() {
X x;
callback_specialization<X> c(x, &X::y);
callback& ref(c);
c();
return 0;
}
This prints "ok".
Tested on VS2008 express.
Please see this
Callback in C++, template member? (2)

Python's PubSub/observer Pattern for C++?

i'm looking for a C++ replacement of the Python PubSub Library in which i don't have to connect a signal with a slot or so, but instead can register for a special Kind of messages, without knowing the object which can send it.
Perhaps you misunderstand what signals and slots are. With signals and slots you don't have to know who sends signals. Your "client" class just declares slots, and an outside manager can connect signals to them.
I recommend you to check out Qt. It's an amazing cross-platform library with much more than just GUI support. It has a convenient and efficient implementation of signals and slots which you can use.
These days it's also licensed with LGPL (in addition to GPL and commercial), so you can use it for practically any purpose.
Re your clarification comment, why not raise an exception for the error? The parent can notify the GUI, or alternatively the GUI can register for a signal the parent emits. This way the parent also doesn't have to know about the GUI.
Can you use the boost libraries? If so then combining the function and bind libraries allows you to do the following. You may be able to do the same using the tr1 functionality if your compiler supports it.
#include <iostream>
#include <list>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function< void() > EVENT_T ;
template<typename F>
class Subject
{
public:
virtual void attach ( F o )
{
obs_.push_back ( o );
}
virtual void notify()
{
for ( typename std::list<F>::iterator i = obs_.begin(); i != obs_.end(); ++i )
( *i ) ();
}
private:
std::list<F> obs_;
} ;
class Button : public Subject<EVENT_T>
{
public:
void onClick()
{
notify() ;
};
};
class Player
{
public:
void play()
{
std::cout << "play" << std::endl ;
}
void stop()
{
std::cout << "stop" << std::endl ;
}
};
class Display
{
public:
void started()
{
std::cout << "Started playing" << std::endl ;
}
};
Button playButton ;
Button stopButton ;
Player thePlayer;
Display theDisplay ;
int main ( int argc, char **argv )
{
playButton.attach ( boost::bind ( &Player::play, &thePlayer ) );
playButton.attach ( boost::bind ( &Display::started, &theDisplay ) );
stopButton.attach ( boost::bind ( &Player::stop, &thePlayer ) );
playButton.onClick() ;
stopButton.onClick() ;
return 0;
}
So when you run this you get:
play
Started playing
stop
Press any key to continue.
So.. is this the kind of thing you are looking for?
See here and here for the source of most of this code.
EDIT: The boost::signal library might also do what you want.
Why don't you just implement one? It's not a complicated pattern (well, depending what you really want). Anyway, I already implemented a quick and dirty one some time ago. It is not optimized, synchronous and single threaded. I hope you can use it to make your own.
#include <vector>
#include <iostream>
#include <algorithm>
template<typename MESSAGE> class Topic;
class Subscriber;
class TopicBase
{
friend class Subscriber;
private:
virtual void RemoveSubscriber(Subscriber* subscriber)=0;
};
template<typename MESSAGE>
class Topic : public TopicBase
{
friend class Subscriber;
private:
class Callable
{
public:
Callable(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
:m_subscriber(subscriber)
,m_method(method)
{
}
void operator()(const MESSAGE& message)
{
(m_subscriber->*m_method)(message);
}
bool operator==(const Callable& other) const
{
return m_subscriber == other.m_subscriber && m_method == other.m_method;
}
public:
Subscriber* m_subscriber;
void (Subscriber::*m_method)(const MESSAGE&);
};
public:
~Topic()
{
//unregister each subscriber
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
std::vector<TopicBase*>& topics = i->m_subscriber->m_topics;
for(std::vector<TopicBase*>::iterator ti = topics.begin();;)
{
ti = std::find(ti, topics.end(), this);
if(ti == topics.end()) break;
ti = topics.erase(ti);
}
}
}
void SendMessage(const MESSAGE& message)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
(*i)(message);
}
}
private:
void Subscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
m_subscribers.push_back(Callable(subscriber, method));
subscriber->m_topics.push_back(this);
}
void Unsubscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
std::vector<Callable>::iterator i = std::find(m_subscribers.begin(), m_subscribers.end(), Callable(subscriber, method));
if(i != m_subscribers.end())
{
m_subscribers.erase(i);
subscriber->m_topics.erase(std::find(subscriber->m_topics.begin(), subscriber->m_topics.end(), this)); //should always find one
}
}
virtual void RemoveSubscriber(Subscriber* subscriber)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin() ; i != m_subscribers.end(); i++)
{
if(i->m_subscriber == subscriber)
{
m_subscribers.erase(i);
break;
}
}
}
private:
std::vector<Callable> m_subscribers;
};
class Subscriber
{
template<typename T> friend class Topic;
public:
~Subscriber()
{
for(std::vector<TopicBase*>::iterator i = m_topics.begin(); i !=m_topics.end(); i++)
{
(*i)->RemoveSubscriber(this);
}
}
protected:
template<typename MESSAGE, typename SUBSCRIBER>
void Subscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Subscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
template<typename MESSAGE, typename SUBSCRIBER>
void Unsubscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Unsubscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
private:
std::vector<TopicBase*> m_topics;
};
// Test
Topic<int> Topic1;
class TestSubscriber1 : public Subscriber
{
public:
TestSubscriber1()
{
Subscribe(Topic1, &TestSubscriber1::onTopic1);
}
private:
void onTopic1(const int& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
class TestSubscriber2 : public Subscriber
{
public:
void Subscribe(Topic<const char*> &subscriber)
{
Subscriber::Subscribe(subscriber, &TestSubscriber2::onTopic);
}
void Unsubscribe(Topic<const char*> &subscriber)
{
Subscriber::Unsubscribe(subscriber, &TestSubscriber2::onTopic);
}
private:
void onTopic(const char* const& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
int main()
{
Topic<const char*>* topic2 = new Topic<const char*>();
{
TestSubscriber1 testSubscriber1;
Topic1.SendMessage(42);
Topic1.SendMessage(5);
}
Topic1.SendMessage(256);
TestSubscriber2 testSubscriber2;
testSubscriber2.Subscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Unsubscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Subscribe(*topic2);
delete topic2;
return 0;
}