I've been trying to implement a C#-like event system in C++ with the tr1 function templates used to store a function that handles the event.
I created a vector so that multiple listeners can be attached to this event, i.e.:
vector< function<void (int)> > listenerList;
I'd like to be able to remove a handler from the list to stop a listener receiving events.
So, how can I find the entry in this list that corresponds to a given listener? Can I test if a 'function' object in the list refers to a particular function?
Thanks!
EDIT: Having looked into the boost::signal approach, it seems it's probably implemented using a token system as some of you have suggested. Here's some info on this. An observer retains a "Connection" object when they attach to an event, and this connection object is used to disconnect if needed. So it looks like whether you use Boost or roll your own with tr1, the basic principle's the same. i.e. it will be a bit clumsy :)
I don't know if you're locked into std C++ and tr1, but if you aren't, it seems like your problem could be completely avoided if you just used something like boost::signal and boost::bind to solve your original problem - creating an event system - instead of trying to roll your own.
Okay, you got me working. The hard part is trying to match the exact usage pattern of C# events. If you skip that, there are MUCH easier ways to do what you're asking. (My co-worker Jason uses a Notifier object all over the place.) Anyway, here's the incredibly boring code which does what you want. Unfortunately, it doesn't allow you to pass parameters from the Subject to the Observer. To do that, you'd need to add even more smarts.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <list>
#include <algorithm>
#include <boost/tr1/functional.hpp>
#include <boost/tr1/memory.hpp>
using namespace std;
using namespace std::tr1;
template <typename T>
class ObserverHandle
{
public:
typedef boost::function<void (T*)> const UnderlyingFunction;
ObserverHandle(UnderlyingFunction underlying)
: _underlying(new UnderlyingFunction(underlying))
{
}
void operator()(T* data) const
{
(*_underlying)(data);
}
bool operator==(ObserverHandle<T> const& other) const
{
return (other._underlying == _underlying);
}
private:
shared_ptr<UnderlyingFunction> const _underlying;
};
class BaseDelegate
{
public:
virtual bool operator==(BaseDelegate const& other)
{
return false;
}
virtual void operator() () const = 0;
};
template <typename T>
class Delegate : public BaseDelegate
{
public:
Delegate(T* observer, ObserverHandle<T> handle)
: _observer(observer),
_handle(handle)
{
}
virtual bool operator==(BaseDelegate const& other)
{
BaseDelegate const * otherPtr = &other;
Delegate<T> const * otherDT = dynamic_cast<Delegate<T> const *>(otherPtr);
return ((otherDT) &&
(otherDT->_observer == _observer) &&
(otherDT->_handle == _handle));
}
virtual void operator() () const
{
_handle(_observer);
}
private:
T* _observer;
ObserverHandle<T> _handle;
};
class Event
{
public:
template <typename T>
void add(T* observer, ObserverHandle<T> handle)
{
_observers.push_back(shared_ptr<BaseDelegate>(new Delegate<T>(observer, handle)));
}
template <typename T>
void remove(T* observer, ObserverHandle<T> handle)
{
// I should be able to come up with a bind2nd(equals(dereference(_1))) kind of thing, but I can't figure it out now
Observers::iterator it = find_if(_observers.begin(), _observers.end(), Compare(Delegate<T>(observer, handle)));
if (it != _observers.end())
{
_observers.erase(it);
}
}
void operator()() const
{
for (Observers::const_iterator it = _observers.begin();
it != _observers.end();
++it)
{
(*(*it))();
}
}
private:
typedef list<shared_ptr<BaseDelegate>> Observers;
Observers _observers;
class Compare
{
public:
Compare(BaseDelegate const& other)
: _other(other)
{
}
bool operator() (shared_ptr<BaseDelegate> const& other) const
{
return (*other) == _other;
}
private:
BaseDelegate const& _other;
};
};
// Example usage:
class SubjectA
{
public:
Event event;
void do_event()
{
cout << "doing event" << endl;
event();
cout << "done" << endl;
}
};
class ObserverA
{
public:
void test(SubjectA& subject)
{
subject.do_event();
cout << endl;
subject.event.add(this, _observe);
subject.do_event();
subject.event.remove(this, _observe);
cout << endl;
subject.do_event();
cout << endl;
subject.event.add(this, _observe);
subject.event.add(this, _observe);
subject.do_event();
subject.event.remove(this, _observe);
subject.do_event();
subject.event.remove(this, _observe);
cout << endl;
}
void observe()
{
cout << "..observed!" << endl;
}
private:
static ObserverHandle<ObserverA> _observe;
};
// Here's the trick: make a static object for each method you might want to turn into a Delegate
ObserverHandle<ObserverA> ObserverA::_observe(boost::bind(&ObserverA::observe, _1));
int _tmain(int argc, _TCHAR* argv[])
{
SubjectA sa;
ObserverA oa;
oa.test(sa);
return 0;
}
And here's the output:
doing event
done
doing event
..observed!
done
doing event
done
doing event
..observed!
..observed!
done
doing event
..observed!
done
FAQ #1 in the boost function documentation seems to address your question - and the easy answer is "no".
The proposal (section IIIb.) states they will not be comparable in any way. If you attach some extra information to them, you can easily identify each callback. For instance, if you simply define a struct wrapping the function pointer, you can remove them (assuming you have the same struct you inserted). You can also add some fields to the struct (like an automatically generated guid the client can hold on to) and compare against that.
If you are storing function pointers only (and not other functors that match the signature required), this is easy (see code below). But in general, the answer, like other posters have said, is no. In that case, you probably want to store your functors in a hash, as values, with keys being something the user supplies on adding and removing.
The code below demonstrates how to get the functor/pointer object that is to be called. To use it, you must know the exact type of the object to extract (i.e., the typeid of the type you specify must match the typeid of the contained functor/pointer).
#include <cstdio>
#include <functional>
using std::printf;
using std::tr1::function;
int main(int, char**);
static function<int (int, char**)> main_func(&main);
int
main(int argc, char** argv)
{
printf("%p == %p\n", *main_func.target<int (*)(int, char**)>(), &main);
return 0;
}
What about
map<key-type, function<void (int)> > listeners;
I had a similar problem and found a solution to it. I used some C++0x features, but only for convenience, they are not an essential part. Take a look here:
> Messaging system: Callbacks can be anything
Related
I've written the most basic Event System I can think of. I come from a javascript background so I followed the On, Off, Emit syntax. The intention is to be able to create an EventSystem that can Emit any type of derived Event object and have the appropriate handlers called.
Please note, I am stuck in C++98 for reasons
So far my best idea is to have a simple Event object and a typedef for each Event type to handle it.
class Event {};
class AlarmEvent : Event {};
class ErrorEvent : Event {};
typedef void (*EventHandler)(Event event);
typedef void (*AlarmEventHandler)(AlarmEvent event);
typedef void (*ErrorEventHandler)(ErrorEvent event);
My issue is I want my modules to be able to attach as easy as possible.
int main()
{
Module module;
EventSystem es;
Event shutdown_event("shutdown");
AlarmEvent alarm_event("alarm", "Oh crap");
es.On("shutdown", module.OnEvent);
es.On("shutdown", module.OnEvent);
es.On("alarm", module.OnAlarmEvent);
es.Emit(shutdown_event);
es.Emit(alarm_event);
}
But looking at the EventSystem
class EventSystem {
public:
void On(std::string id, EventHandler handler);
void Emit(Event event);
void GetEventHandlers(std::string id, std::vector<EventHandler> *&handlers);
std::map<std::string, std::vector<EventHandler> > events;
};
I'd need an On, GetEventHandlers, and events property for every event type. This would quickly become terrible. Is there a better path where I can use a template to allow EventSystem to stay as simple as possible?
C++98 is old, older than variadic templates. The following emulates variadic templates with linked lists, which is very much suboptimal, but it should work.
// linked lists for "variadic" templates
struct Nil { };
template<typename X, typename XS>
struct Cons { };
// utility type
struct BlackHole {
template<typename T>
BlackHole(const T&) { }
};
// anything can be converted to a BlackHole implicitly, but it's a "worse"
// conversion than being converted to a base class
// I would template your event system over every event type
// this implementation only works properly if more derived events appear before their bases
template<typename Events> // e.g. Events = Cons<AlarmEvent, Cons<ErrorEvent, Cons<Event, Nil>>>
class EventSystem;
template<>
class EventSystem<Nil> {
protected:
// see below for Emit/EmitEmitted thing
// usage of BlackHole means that e.g. if calling with AlarmEvent
// and only overloads for Event and BlackHole are visible
// then the former will be chosen, since the latter conversion is worse
// can't just say template<typename T> EmitEmitted(T const&) { }
void EmitEmitted(BlackHole) { }
public:
// these overloads exist so the using declarations ahead don't fail
// for maximum type-safety, create a private type and
// make it an argument of each, so they can never be called
// using Emit/EmitEmitted creates type safety; again, see below
void Emit() { }
// On has easy type safety: you just can't call it for an unknown type
void On() { }
// GetEventHandlers doesn't really make sense anyway
// I don't think you need it, you can't have a vector of mixed handlers
// so why bother?
};
template<typename X, typename XS>
class EventSystem<Cons<X, XS> > : public EventSystem<XS> {
std::vector<void (*)(X)> handlers;
protected:
// "forward" all the EmitEmitted overloads made for XS
using EventSystem<XS>::EmitEmitted;
// overload for the specific case of an X
void EmitEmitted(X x) {
// fire all of the X-specific handlers
for(typename std::vector<void (*)(X)>::iterator i = handlers.begin(); i != handlers.end(); ++i) {
(*i)(x);
}
// call the rest of the handlers
EventSystem<XS>::EmitEmitted(x);
}
public:
// more "forwarding"
using EventSystem<XS>::Emit;
void Emit(X x) {
return EmitEmitted(x);
}
// suppose you have an EventSystem<Cons<std::string, Nil> >
// if you Emit an int, say, then you want this to fail
// thus the overload of Emit in EventSystem<Nil> should not be
// a catch-all or anything
// however, if you emit a std::string, then you need to recursively
// emit from EventSystem<Nil>, to handle any handlers for superclasses
// now you don't want it to explode
// solution? two functions
// Emit is the public entry point, and fails on unknown types
// EmitEmitted is named so because, once it's called, the type
// is known to be known, and will/has been emitted by at least one layer
// it no-ops once the base case is reached
// it is protected, and it is where the actual logic is
// easy now, right?
using EventSystem<XS>::On;
void On(void (*handler)(X)) {
handlers.push_back(handler);
}
};
Example usage:
struct Event {
std::string message;
Event(std::string message) : message(message) { }
};
void HandleEvent(Event e) {
std::cerr << e.message << "\n";
}
class AlarmEvent : public Event {
int hour;
int minute;
static std::string BuildMessage(int hour, int minute) {
std::stringstream builder;
builder << "Alarm: " << std::setfill('0');
builder << std::setw(2) << hour << ":";
builder << std::setw(2) << minute;
return builder.str();
}
friend void HandleAlarm(AlarmEvent);
public:
AlarmEvent(int hour, int minute) : Event(BuildMessage(hour, minute)), hour(hour), minute(minute) { }
};
void HandleAlarm(AlarmEvent a) {
// please ignore the fact that this is very stupid
if((a.hour + (a.minute / 60)) % 24 < 12) std::cerr << "AM Alarm\n";
else std::cerr << "PM Alarm\n";
}
struct ErrorEvent : Event {
ErrorEvent(std::string message) : Event(message) { }
};
void HandleError(ErrorEvent) {
static int count = 1;
std::cerr << "Error " << count++ << "\n";
}
int main() {
EventSystem<Cons<AlarmEvent, Cons<ErrorEvent, Cons<Event, Nil> > > > system;
// all handled by overload resolution
// no need to say what type you're dealing with
system.On(HandleEvent);
system.On(HandleAlarm);
system.On(HandleError);
// doesn't work
// system.On(std::exit)
system.Emit(ErrorEvent("Bad things"));
system.Emit(AlarmEvent(2, 30));
system.Emit(Event("Something happened"));
system.Emit(ErrorEvent("More bad things"));
system.Emit(AlarmEvent(11, 67));
// doesn't work
// system.Emit(5);
}
Not sure that all the example code is C++98, but that doesn't matter. It appears to work nicely. Also, there's a lot of copying going on here. It may be advisable to change handlers from void (*)(T) (which necessitates a copy) to void (*)(T&) or void (*)(T const&).
If your functions took references or pointers, then you would be able to pass polymorphic child types into them. So then you only need one type of function ptr.
typedef void (*EventHandler)(Event& event);
or
typedef void (*EventHandler)(Event* event);
How to appropriately cache userData that is generated from user's callbackBegin() and send it to user's callbackEnd().
Simple version (No userData - demo)
I want to create a complex database that support callback. For MCVE, let's say it is MyArray.
Here is a simple array class that supports callback but no userData.
#include <iostream>
template<class Derived>class MyArray{ //library - I design it.
public: void push_back(int s){
static_cast<Derived*>(this)->callbackBegin(s);
//do something about array
static_cast<Derived*>(this)->callbackEnd(s);
}
//other fields / functions
};
class Callback : public MyArray<Callback>{ //user's class
public: void callbackBegin(int s){
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s){
std::cout<<"callbackEnd"<<std::endl;
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd
return 0;
}
It works correctly.
The next step : I want to pass some userData from Callback::callbackBegin() to Callback::callbackEnd().
For example, userData is a clock time when Callback::callbackBegin() is called.
My poor solution (void*& userdata : demo)
Here is my attempt to implement it :-
#include <iostream>
#include <time.h>
template<class Derived>class MyArray{
public: void push_back(int s){
void* userData=nullptr; //#
static_cast<Derived*>(this)->callbackBegin(s,userData); //# ugly
//do something about array
static_cast<Derived*>(this)->callbackEnd(s,userData); //# ugly
}
};
class Callback : public MyArray<Callback>{
public: void callbackBegin(int s,void*& userData){ //#
userData=new clock_t(clock()); //# danger
std::cout<<"callbackBegin"<<std::endl;
}
public: void callbackEnd(int s,void*& userData){ //#
clock_t* userDataTyped=static_cast<clock_t*>(userData);
clock_t clock2=clock();
clock_t different=clock2 - (*userDataTyped);
std::cout<<"callbackEnd time(second)="
<<((float)different)/CLOCKS_PER_SEC<<std::endl;
delete userDataTyped; //# danger
}
};
int main() {
Callback c;
c.push_back(5); //print: callbackBegin callbackEnd time(second)=8.5e-05
return 0;
}
It also works correctly, but I believe it is a bad design (at various #) :-
new/delete in 2 places : potential memory leaking.
Strong pointer is preferred, but I don't know how to.
static_cast<clock_t*>(userData) is code-smell, at least for me.
(minor issue) an extra ugly parameter void*&
Question: What are design patterns / C++ magic to avoid such issues, while make MyArray concise, easy to use, maintainable (i.e. not much worse than the Simple version)?
Other notes:
In real cases, <5% of user's callback classes need userData.
Thus, I feel very reluctant to add void&* as an extra parameter.
Clarify: (edited) The minority cases usually need different types of userData e.g. Callback1 need clock_t, Callback2 need std::string, etc.
Proposed solution should restrain from using std::function<> or virtual function, because the performance is a major concern here.
Thank.
Pass data through a void pointer is a good C solution but (IMHO) not a C++ (specially: not a C++11/c++14/C++17, with auto and std::tuple) good one.
So I suggest to return a value from callbackBegin() and pass the value as first argument to `callbackEnd(); something like
auto r = static_cast<Derived*>(this)->callbackBegin(s);
static_cast<Derived*>(this)->callbackEnd(r, s);
Observe (C++11 and newer magic) that using auto as type of the value returned by callbackBegin(), you can return different types from different `callbackBegin().
Bonus suggestion: be more generic in MyArray::push_back(): using variadic templates, there is no need of fix the number and the types of arguments received by callbackBack() and callbackEnd().
Using variadic templates you can modify push_back() as follows
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<Derived*>(this)->callbackBegin(args...);
static_cast<Derived*>(this)->callbackEnd(r, args...);
}
The following is a full working example with two different callback classes (with different number of arguments and different return types)
#include <tuple>
#include <iostream>
template <typename derT>
struct myA
{
template <typename ... Args>
void push_back (Args const & ... args)
{
auto r = static_cast<derT*>(this)->callbackBegin(args...);
static_cast<derT*>(this)->callbackEnd(r, args...);
}
};
struct cb1 : public myA<cb1>
{
int callbackBegin (int s)
{ std::cout << "cb1 b" << std::endl; return s+5; }
void callbackEnd (int r, int s)
{ std::cout << "cb1 e -" << r << ", " << s << std::endl; }
};
struct cb2 : public myA<cb2>
{
std::tuple<std::string, int> callbackBegin (std::string const & name,
int num)
{ std::cout << "cb2 b" << std::endl; return {name+";", num+1}; }
void callbackEnd (std::tuple<std::string, int> const &,
std::string const & name, int num)
{ std::cout << "cb2 e -" << name << ", " << num << std::endl; }
};
int main ()
{
cb1 c1;
c1.push_back(5);
cb2 c2;
c2.push_back("string arg", 7);
return 0;
}
std::any would allow you to hold clock_t (or any other) object and do away with the void* pointers, however that's a C++17 concept and not yet widely available (although there are implementations such as boost::any).
In the meantime, your code may benefit from a little composition over inheritance, as array and callback are conceptually pretty different and don't seem to belong in the same inheritance hierarchy. So, preferring composition, the code might look something like:
template<class T> struct ICallback
{
virtual void callbackBegin(int s, std::unique_ptr<T>& p) = 0;
virtual void callbackEnd(int s, std::unique_ptr<T>& p) = 0;
};
template<class T> class MyArray
{
public:
MyArray(std::shared_ptr<ICallback<T>> cb) { callback = cb; }
void push_back(int s)
{
callback->callbackBegin(s, usrDataPtr);
//do something about array
callback->callbackEnd(s, usrDataPtr);
}
protected:
std::shared_ptr<ICallback<T>> callback;
std::unique_ptr<T> usrDataPtr;
};
class ClockCallback : public ICallback<clock_t>
{
public:
void callbackBegin(int s, std::unique_ptr<clock_t>& c){
c = std::make_unique<clock_t>(clock());
std::cout << "callbackBegin" << std::endl;
}
void callbackEnd(int s, std::unique_ptr<clock_t>& c){
clock_t clock2 = clock();
clock_t different = clock2 - (*c);
std::cout << "callbackEnd time(second)="
<< ((float)different) / CLOCKS_PER_SEC << std::endl;
}
};
int main() {
std::shared_ptr<ClockCallback> c = std::make_shared<ClockCallback>();
MyArray<clock_t> ma(c);
ma.push_back(7);
return 0;
}
You can use a smart pointer to avoid manually deleting your userData
std::unique_ptr<clock_t> userData;
pass it as a reference to your callbacks
void callbackBegin(int s, std::unique_ptr<clock_t> &userData)
and initialize it this way
userData = std::make_unique<clock_t>(clock())
The C++ magic you're asking about is a known as a virtual method. Virtual method is one of the C++ native ways to implement the callback:
class MyArray{
public:
void push_back(int s) {
const auto userData = callbackBegin(s); //# beautiful
//do something about array
callbackEnd(s, userData); //# beautiful
}
private:
virtual clock_t callbackBegin(int) const = 0;
virtual void callbackEnd(int, const clock_t&) const = 0;
};
class Callback : public MyArray{
clock_t callbackBegin(int s) const final {
std::cout<<"callbackBegin"<<std::endl;
return clock(); //# safe
}
void callbackEnd(int s,const clock_t& userData) const final { //#
const auto different = clock() - userDataTyped;
std::cout << "callbackEnd time(second)=";
std::cout << different/CLOCKS_PER_SEC << std::endl;
//# safe
}
};
Another way is to pass two callable objects to the MyArray ctor and using those objects in the push_back method. The callable objects shall store calls to the relevant class Callback methods. Use std::function to implement those callable objects.
My question is rather simple, however i was unable to find anything about it on google (possibly because i am new to c++ and don't quite know the right terminology for everything yet). My question is, is it possible for me to add a reference to a function in a list, and if so, what is the correct way to do it?
Basically what i'm trying to do is to create an event class that would be able to store function references in a list so that i could do some basic event handling.
What im thinking of doing is something like this:
list<function> fnlist;
void add(function fn) {
fnlist.add(fn);
}
void call() {
for (function &fn: fnlist) {
fn();
}
}
Is something like this possible?
Please note that i would like to avoid using any event libraries if i could do this without any.
Absolutely, this is possible:
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
void quick() {
cout << "quick ";
}
void brown() {
cout << "brown ";
}
void fox() {
cout << "fox ";
}
int main() {
vector<function<void()> > events;
events.push_back(quick);
events.push_back(brown);
events.push_back(fox);
for (auto f : events) {
f();
}
return 0;
}
Use std::function<void()> to hold a functional object that encapsulates a callable that takes no parameters, and does not return a result.
Demo.
Use following :
/* ret_type : Return Type,
arg_type - type of argument (can be multiple, separated by comma)
*/
typedef std::function<ret_type( arg_type )> function ;
std::list < function> fnlist ;
void add(function fn)
{
fnlist.add(fn);
}
void call()
{
for (const auto &fn: fnlist)
{
fn();
}
}
I have a class that has a vector of another class objects as a member. In many functions of this class I have to do same operation on all the objects in the vector:
class Small
{
public:
void foo();
void bar(int x);
// and many more functions
};
class Big
{
public:
void foo()
{
for (size_t i = 0; i < VectorOfSmalls.size(); i++)
VectorOfSmalls[i]->foo();
}
void bar(int x)
{
for (size_t i = 0; i < VectorOfSmalls.size(); i++)
VectorOfSmalls[i]->bar(x);
}
// and many more functions
private:
vector<Small*> VectorOfSmalls;
};
I want to simplify the code, and find a way not to duplicate going other the vector in every function.
I've considered creating a function that receives a pointer to function, and calls the pointed function on every member of a vector. But I am not sure that using pointers to functions in C++ is a good idea.
I have also been thinking about functors and functionoids, but it will force me to create a class per each function and it sounds like an overkill.
Another possible solution is creating a function that receives a string, and calls the command according to the string:
void Big::call_command(const string & command)
{
for (size_t i = 0; i < VectorOfSmalls.size(); i++)
{
if (command == "foo")
VectorOfSmalls[i]->foo();
else if (command == "bar")
VectorOfSmalls[i]->bar();
}
}
void Big::foo()
{
call_command("foo");
}
But it might work slow (unneeded creation of a string instead of just a function call), and also creates a problem if functions have different signature.
So what would you recommend? Should I leave everything the same as it is now?
EDIT: I can use only STL and not boost (old compilers).
Well you can rewrite the for loops to use iterators and more of the STL like this:
void foo() {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo));
}
void bar() {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar));
}
beyond that, you could use some macros to avoid retyping that a lot, but I'm not a huge fan of that. Personally, I like the multiple functions over the single one which takes a command string. As it gives you more versatility over how the decision is made.
If you do go with a single function taking a param to decide which to do, I would use an enum and a switch like this, it would be more efficient than strings and a cascading if. Also, in your example you have the if to decide which to do inside the loop. It is more efficient to check outside the loop and have redundant copies of the loop since "which command" only needs to be decided once per call. (NOTE: you can make the command a template parameter if it is known at compile time, which it sounds like it is).
class Big {
public:
enum Command {
DO_FOO,
DO_BAR
};
void doit(Command cmd) {
switch(cmd) {
case DO_FOO:
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::foo));
break;
case DO_BAR:
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(&Small::bar));
break;
}
};
Also, as you mentioned, it is fairly trivial to replace the &Small::whatever, what a member function pointer and just pass that as a parameter. You can even make it a template too.
class Big {
public:
template<void (Small::*fn)()>
void doit() {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn));
}
};
Then you can do:
Big b;
b.doit<&Small::foo>();
b.doit<&Small::bar>();
The nice thing about both this and the regular parameter methods is that Big doesn't need to be altered if you change small to have more routines! I think this is the preferred method.
If you want to be able to handle a single parameter, you'll need to add a bind2nd too, here's a complete example:
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
class Small {
public:
void foo() { std::cout << "foo" << std::endl; }
void bar(int x) { std::cout << "bar" << std::endl; }
};
class Big {
public:
template<void (Small::*fn)()>
void doit() {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::mem_fun(fn));
}
template<class T, void (Small::*fn)(T)>
void doit(T x) {
std::for_each(VectorOfSmalls.begin(), VectorOfSmalls.end(), std::bind2nd(std::mem_fun(fn), x));
}
public:
std::vector<Small *> VectorOfSmalls;
};
int main() {
Big b;
b.VectorOfSmalls.push_back(new Small);
b.VectorOfSmalls.push_back(new Small);
b.doit<&Small::foo>();
b.doit<int, &Small::bar>(5);
}
If you're using the std library, you should take a look at for_each.
You mention that using function pointers in C++ might not be a good idea, but -- allowing your worry is speed -- you have to see if this is even a performance bottleneck area you're in, before worrying.
Try boost::function and boost::bind:
void Big::call_command(const boost::function<void (Small*)>& f)
{
for (size_t i = 0; i < VectorOfSmalls.size(); i++)
{
f(VectorOfSmalls[i]);
}
}
int main()
{
Big b;
b.call_command(boost::bind(&Small::foo, _1));
b.call_command(boost::bind(&Small::bar, _1, 5));
}
I need to bind a method into a function-callback, except this snippet is not legal as discussed in demote-boostfunction-to-a-plain-function-pointer.
What's the simplest way to get this behavior?
struct C {
void m(int x) {
(void) x;
_asm int 3;
}};
typedef void (*cb_t)(int);
int main() {
C c;
boost::function<void (int x)> cb = boost::bind(&C::m, &c, _1);
cb_t raw_cb = *cb.target<cb_t>(); //null dereference
raw_cb(1);
return 0;
}
You can make your own class to do the same thing as the boost bind function. All the class has to do is accept the function type and a pointer to the object that contains the function. For example, this is a void return and void param delegate:
template<typename owner>
class VoidDelegate : public IDelegate
{
public:
VoidDelegate(void (owner::*aFunc)(void), owner* aOwner)
{
mFunction = aFunc;
mOwner = aOwner;
}
~VoidDelegate(void)
{}
void Invoke(void)
{
if(mFunction != 0)
{
(mOwner->*mFunction)();
}
}
private:
void (owner::*mFunction)(void);
owner* mOwner;
};
Usage:
class C
{
void CallMe(void)
{
std::cout << "called";
}
};
int main(int aArgc, char** aArgv)
{
C c;
VoidDelegate<C> delegate(&C::CallMe, &c);
delegate.Invoke();
}
Now, since VoidDelegate<C> is a type, having a collection of these might not be practical, because what if the list was to contain functions of class B too? It couldn't.
This is where polymorphism comes into play. You can create an interface IDelegate, which has a function Invoke:
class IDelegate
{
virtual ~IDelegate(void) { }
virtual void Invoke(void) = 0;
}
If VoidDelegate<T> implements IDelegate you could have a collection of IDelegates and therefore have callbacks to methods in different class types.
Either you can shove that bound parameter into a global variable and create a static function that can pick up the value and call the function on it, or you're going to have to generate per-instance functions on the fly - this will involve some kind of on the fly code-gen to generate a stub function on the heap that has a static local variable set to the value you want, and then calls the function on it.
The first way is simple and easy to understand, but not at all thread-safe or reentrant. The second version is messy and difficult, but thread-safe and reentrant if done right.
Edit: I just found out that ATL uses the code generation technique to do exactly this - they generate thunks on the fly that set up the this pointer and other data and then jump to the call back function. Here's a CodeProject article that explains how that works and might give you an idea of how to do it yourself. Particularly look at the last sample (Program 77).
Note that since the article was written DEP has come into existance and you'll need to use VirtualAlloc with PAGE_EXECUTE_READWRITE to get a chunk of memory where you can allocate your thunks and execute them.
#include <iostream>
typedef void(*callback_t)(int);
template< typename Class, void (Class::*Method_Pointer)(void) >
void wrapper( int class_pointer )
{
Class * const self = (Class*)(void*)class_pointer;
(self->*Method_Pointer)();
}
class A
{
public:
int m_i;
void callback( )
{ std::cout << "callback: " << m_i << std::endl; }
};
int main()
{
A a = { 10 };
callback_t cb = &wrapper<A,&A::callback>;
cb( (int)(void*)&a);
}
i have it working right now by turning C into a singleton, factoring C::m into C::m_Impl, and declaring static C::m(int) which forwards to the singleton instance. talk about a hack.