Which Callback implementation is better?

D

Damien

Hi all,

I'm messing around with various signal/slot mechanisms, trying to build
something lean and fast. I've used libsigc++, and Sarah Thompson's at
sigslot.sourceforge.net, and most of the others you can find by
Googling, but I wanted to try doing it myself and needed some advice on
different approaches.

Most signal/slot libraries are based on template classes containing a
pointer-to-object and pointer-to-memfunc. You can also do callbacks or
signals with a pointer or reference to the object only, and use
templating to create a signal or callback based on an object and a
templated member function call. The shortest code I can cobble
together that demonstrates both approaches is below, which I threw into
a main.cpp.

#include <iostream>

template <class Arg>
class Callback1ArgBase
{
public:
Callback1ArgBase(){}
virtual ~Callback1ArgBase(){}
virtual void operator()(Arg& arg){}
};

template <class T, class Arg, void (T::*F)(Arg)>
class Callback1ArgTemplate : public Callback1ArgBase<Arg>
{
public:
Callback1ArgTemplate(T& t):eek:bject(t){}
virtual ~Callback1ArgTemplate(){}
virtual void operator()(Arg& arg){(object.*F)(arg);}

private:
T& object;
};


template <class T, class Arg>
class Callback1ArgMemPtr : public Callback1ArgBase<Arg>
{
public:
Callback1ArgMemPtr(T* t, void (T::*f)(Arg)):eek:bject(t),func(f){}
virtual void operator()(Arg& arg){(object->*func)(arg);}

private:
T* object;
void (T::*func)(Arg);
};

class Client
{
public:
Client(){}
~Client(){}
void TellMeInt(int i)
{
std::cout << "\n Wotcha. Callback fired! Int is " << i <<
"\n";
}
};

template<class Arg>
class Server
{
public:
Server():callbk1argtemplate(0),callbk1argmemptr(0){}
~Server()
{
if (callbk1argtemplate)delete callbk1argtemplate;
if (callbk1argmemptr)delete callbk1argmemptr;
}

//create a templated callback
template<class T, void (T::*F)(Arg)> void
BindCallback1ArgTemplate(T& t)
{
callbk1argtemplate = new Callback1ArgTemplate<T, Arg, F>(t);
}

//create a member function pointer callback
template<class T> void BindCallback1ArgMemPtr(T* t, void
(T::*F)(Arg))
{
callbk1argmemptr = new Callback1ArgMemPtr<T, Arg>(t, F);
}

void DoSomethingArg(Arg arg)
{
std::cout << "\n This is Server doing something with an arg on
the template version.\n";
(*callbk1argtemplate)(arg);
std::cout << "\n This is Server doing something with an arg on
the member pointer version.\n";
(*callbk1argmemptr)(arg);
}
private:
Callback1ArgBase<Arg>* callbk1argtemplate;
Callback1ArgBase<Arg>* callbk1argmemptr;

};

int main()
{
Server<int> server;
Client client;
server.BindCallback1ArgTemplate<Client, &Client::TellMeInt>(client);
server.BindCallback1ArgMemPtr(&client, &Client::TellMeInt);
int fred = -32767;
server.DoSomethingArg(fred);
return 0;
}

Both methods work, but the Callback1ArgTemplate version is smaller
because it doesn't contain a member function pointer (unless I
misunderstand how the compiler builds template classes). Without a
member function pointer you can't rebind to a different member
function. I'm an engineer, not a Computer Science grad, so could
anyone with a bit of CompSci experience comment on these approaches?
Also, I noticed that server.BindCallback1ArgMemPtr... call doesn't
require the addition of the <Client> template part, I assume that's
because it's implicit in the arguments to the function.

Thanks in advance,

Damien
 
A

AnonMail2005

Damien said:
Hi all,

I'm messing around with various signal/slot mechanisms, trying to build
something lean and fast. I've used libsigc++, and Sarah Thompson's at
sigslot.sourceforge.net, and most of the others you can find by
Googling, but I wanted to try doing it myself and needed some advice on
different approaches.

Most signal/slot libraries are based on template classes containing a
pointer-to-object and pointer-to-memfunc. You can also do callbacks or
signals with a pointer or reference to the object only, and use
templating to create a signal or callback based on an object and a
templated member function call. The shortest code I can cobble
together that demonstrates both approaches is below, which I threw into
a main.cpp.

#include <iostream>

template <class Arg>
class Callback1ArgBase
{
public:
Callback1ArgBase(){}
virtual ~Callback1ArgBase(){}
virtual void operator()(Arg& arg){}
};

template <class T, class Arg, void (T::*F)(Arg)>
class Callback1ArgTemplate : public Callback1ArgBase<Arg>
{
public:
Callback1ArgTemplate(T& t):eek:bject(t){}
virtual ~Callback1ArgTemplate(){}
virtual void operator()(Arg& arg){(object.*F)(arg);}

private:
T& object;
};


template <class T, class Arg>
class Callback1ArgMemPtr : public Callback1ArgBase<Arg>
{
public:
Callback1ArgMemPtr(T* t, void (T::*f)(Arg)):eek:bject(t),func(f){}
virtual void operator()(Arg& arg){(object->*func)(arg);}

private:
T* object;
void (T::*func)(Arg);
};

class Client
{
public:
Client(){}
~Client(){}
void TellMeInt(int i)
{
std::cout << "\n Wotcha. Callback fired! Int is " << i <<
"\n";
}
};

template<class Arg>
class Server
{
public:
Server():callbk1argtemplate(0),callbk1argmemptr(0){}
~Server()
{
if (callbk1argtemplate)delete callbk1argtemplate;
if (callbk1argmemptr)delete callbk1argmemptr;
}

//create a templated callback
template<class T, void (T::*F)(Arg)> void
BindCallback1ArgTemplate(T& t)
{
callbk1argtemplate = new Callback1ArgTemplate<T, Arg, F>(t);
}

//create a member function pointer callback
template<class T> void BindCallback1ArgMemPtr(T* t, void
(T::*F)(Arg))
{
callbk1argmemptr = new Callback1ArgMemPtr<T, Arg>(t, F);
}

void DoSomethingArg(Arg arg)
{
std::cout << "\n This is Server doing something with an arg on
the template version.\n";
(*callbk1argtemplate)(arg);
std::cout << "\n This is Server doing something with an arg on
the member pointer version.\n";
(*callbk1argmemptr)(arg);
}
private:
Callback1ArgBase<Arg>* callbk1argtemplate;
Callback1ArgBase<Arg>* callbk1argmemptr;

};

int main()
{
Server<int> server;
Client client;
server.BindCallback1ArgTemplate<Client, &Client::TellMeInt>(client);
server.BindCallback1ArgMemPtr(&client, &Client::TellMeInt);
int fred = -32767;
server.DoSomethingArg(fred);
return 0;
}

Both methods work, but the Callback1ArgTemplate version is smaller
because it doesn't contain a member function pointer (unless I
misunderstand how the compiler builds template classes). Without a
member function pointer you can't rebind to a different member
function. I'm an engineer, not a Computer Science grad, so could
anyone with a bit of CompSci experience comment on these approaches?
Also, I noticed that server.BindCallback1ArgMemPtr... call doesn't
require the addition of the <Client> template part, I assume that's
because it's implicit in the arguments to the function.

Thanks in advance,

Damien
For callbacks, use the boost function and boost bind libraries. You
should at the very least evaluate them to see if the meet your needs.
 
D

Damien

Tried Boost too. Pretty good, but I'm still wondering about what the
experts think of either approach above.

Damien
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top