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)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))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
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)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))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