C++ object for callback with variable parameters list - c++

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.

Related

Calling a templatized std::function stored in a map

I'm attempting to create a base class that will store signals (in the form of an int) and allow me to later use them to call functions specified by the derived class. They are stored in an unordered_map because it's exactly what I need -- 1 signal = 1 function (plus it's fast).
Though, I'm having some trouble calling them, getting a huge error in the form of:
no match for call to ‘(std::unordered_map<int, std::function<void()>, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, std::function<void()> > > >::mapped_type {aka std::function<void()>}) (int&, int&)’
The compile-error is from signals_[_sig](args...);
const int SIGCHANGE = 1;
template<typename... Args>
class Signal {
private:
std::unordered_map< int, std::function<void(Args...)> > signals_;
inline void SetSignal(const int& _sig, std::function<void(Args...)> _func) {
signals_[_sig] = _func;
}
public:
Signal() {}
~Signal() {}
template<typename... Ts>
void Sig(const int& _sig, Ts... args) {
if (signals_.find(_sig) != signals_.end()) {
signals_[_sig](args...);
}
}
};
class Obj : public Signal<> {
private:
int num_;
public:
Obj* child;
void Change(int _num) {
num_ = _num;
child->Sig(SIGCHANGE, _num);
}
void HandleChanged(int _num) {
num_ = _num;
}
};
int main() {
Obj* obj1 = new Obj();
Obj* obj2 = new Obj();
obj1->child = obj2;
obj1->Change(10);
}
Also, I have no idea if I'm using the templates correctly - it's been ages since I last used them. Should each function have its own template? Why do I have to specify the template before the class if I want to use it for a member variable?
As you function has a single int parameter, you need to have
class Obj : public Signal<int>
instead of
class Obj : public Signal<>
The later creates a map with functions prototyped void(), whereas you need a function prototyped void(int).
Also, templatizing the Sig function is useless, because you will not be able to call it with any other set of parameters than Args anyway. So it can simply be
void Sig(const int& _sig, Args... args) {
if (signals_.find(_sig) != signals_.end()) {
signals_[_sig](args...);
}
}
If your goal is to support storing functions with arbitrary prototype, that does need to be done different way, basically via runtime polymorphism (all the items in the map need to be of the same type, so the type itself would need to do the call polymorphism under the hood).
EDIT
One possibility with function prototypes defined according to the signal type. Requires that the signal ints will always be passed as compile-time constants - the different functor for particular signal types are stored in std::tuple:
const int SIGZERO = 0;
const int SIGCHANGE = 1;
const int SIGOTHER = 2;
// non-specialized template intentionally left empty
// (or can provide default prototype)
template<int SIG>
struct SignalPrototype;
template<>
struct SignalPrototype<SIGZERO>
{
typedef std::function< void() > type;
};
template<>
struct SignalPrototype<SIGCHANGE>
{
typedef std::function< void(int) > type;
};
template<>
struct SignalPrototype<SIGOTHER>
{
typedef std::function< void(int, int) > type;
};
class Signal {
private:
std::tuple<
SignalPrototype<SIGZERO>::type,
SignalPrototype<SIGCHANGE>::type,
SignalPrototype<SIGOTHER>::type
> signals_;
protected:
template<int SIG>
inline void SetSignal(typename SignalPrototype<SIG>::type _func) {
std::get<SIG>(signals_) = _func;
}
public:
template<int SIG, typename... Ts>
void Sig(Ts... args) {
SignalPrototype<SIG>::type func = std::get<SIG>(signals_);
if (func)
func(args...);
}
};
struct MyHandler : SignalPrototype<SIGCHANGE>::type
{
void operator()(int x)
{
std::cout << "Called MyHandler with x = " << x << std::endl;
}
};
class Obj : public Signal {
private:
int num_;
public:
Obj* child;
Obj()
{
SetSignal<SIGCHANGE>(MyHandler());
}
void Change(int _num) {
num_ = _num;
child->Sig<SIGZERO>();
child->Sig<SIGCHANGE>(_num);
child->Sig<SIGOTHER>(1, 2);
}
void HandleChanged(int _num) {
num_ = _num;
}
};
(and in general, it could be actually better for Signal to be member of the Obj instead of inheritance)

ARG! Contravarience foils callback plot! Want to change virtual return type

I am working on a AI dynamic link library. It is to be explicitly linked and all of this is handled by a simple header include.
I am at the moment trying to create the code for the DLL to be able to call functions in the main EXE to manipulate the world and also to be able to query functions to learn about the state of the world. I am now at the point where I can call void return functions (be they global functions or member functions) with no parameters.
I am now trying to implement the ability to call functions in the EXE and get the return value from them. (non-void functions) Things are not going well.. I've been trying for a while now trying to find the best way to implement this. I can use boost libraries in the DLL but not in the EXE.
I'm going to do a dump of the relavent code here. I know it is alot but I hope someone will be able to point out how I can improve.
Even if you do not read the code (very understandable) it would be very helpful to know how you would go about tackling this problem in general terms.
Here goes (I've tried to cut out as many unrelated sections of code as I can):
---------------------------------------EXE side header--------------------------------------
typedef void (*Command)();
typedef void (*CommandMF)(int, std::string);
typedef void (*AddEntityFunction)(int&);
typedef void (*AddActionToEntityFunction)(int, Command);
typedef void (*AddActionToEntityFunctionMF)(int, CommandMF, std::string);
typedef void (*UpdateDoubleThinkFunction)();
class MemberFunctionStorageExecute
{
public:
virtual void Execute() const =0;
};
template <class T>
struct MemberFunctionStorage : MemberFunctionStorageExecute
{
typedef void (T::*MemberFunctionWorker)();
MemberFunctionWorker mbw;
T *obj;
virtual void Execute() const
{
(obj->*mbw)();
}
};
typedef std::map<std::string, MemberFunctionStorageExecute*> MemberFunctionsList;
typedef std::map<int, MemberFunctionsList*> ListofLists;
//Template hack to allow static properties inside header
template <class T>
class DoubleThinkInterfaceImpl
{
protected:
static HINSTANCE hinstDLL;
static AddEntityFunction DLLAddEntity;
static AddActionToEntityFunction DLLAddActionToEntity;
static AddActionToEntityFunctionMF DLLAddActionToEntityMF;
static UpdateDoubleThinkFunction DLLUpdateDoubleThink;
static ListofLists m_plistlist;
};
template <class T>
HINSTANCE DoubleThinkInterfaceImpl<T>::hinstDLL;
template <class T>
AddEntityFunction DoubleThinkInterfaceImpl<T>::DLLAddEntity;
template <class T>
UpdateDoubleThinkFunction DoubleThinkInterfaceImpl<T>::DLLUpdateDoubleThink;
template <class T>
AddActionToEntityFunction DoubleThinkInterfaceImpl<T>::DLLAddActionToEntity;
template <class T>
AddActionToEntityFunctionMF DoubleThinkInterfaceImpl<T>::DLLAddActionToEntityMF;
template <class T>
ListofLists DoubleThinkInterfaceImpl<T>::m_plistlist;
class DoubleThinkInterface : protected DoubleThinkInterfaceImpl<int>
{
private:
int m_pid;
MemberFunctionsList m_pmemfunlist;
public:
int ID()
{
return m_pid;
}
DoubleThinkInterface()
{
if(!hinstDLL)
{
hinstDLL = LoadLibrary("DoubleThink.dll");
DLLAddEntity = (AddEntityFunction)GetProcAddress(hinstDLL, "AddEntity");
DLLUpdateDoubleThink = (UpdateDoubleThinkFunction)GetProcAddress(hinstDLL, "Update");
DLLAddActionToEntity = (AddActionToEntityFunction)GetProcAddress(hinstDLL, "AddActionToEntity");
DLLAddActionToEntityMF = (AddActionToEntityFunctionMF)GetProcAddress(hinstDLL, "AddActionToEntityMF");
}
DLLAddEntity(m_pid);
DoubleThinkInterface::m_plistlist.insert(std::pair<int, MemberFunctionsList*>(m_pid, &m_pmemfunlist));
}
~DoubleThinkInterface()
{
//if(hinstDLL != 0)
// FreeLibrary(hinstDLL);
}
void AddAction(Command action)
{
DLLAddActionToEntity(m_pid, action);
}
void Update()
{
DLLUpdateDoubleThink();
}
template <class T>
void AddActionMF(T *object, void (T::*memberfunc)(), std::string actionName)
{
MemberFunctionStorage<T> *store = new MemberFunctionStorage<T>;
store->mbw = memberfunc;
store->obj = object;
m_pmemfunlist.insert(std::pair<std::string, MemberFunctionStorageExecute*>(actionName, store));
DLLAddActionToEntityMF(m_pid, &DoubleThinkInterface::ResolveMF, actionName);
}
static void ResolveMF(int idnum,std::string mfName)
{
ListofLists::iterator lit;
lit = m_plistlist.find(idnum);
MemberFunctionsList::iterator it;
it = lit->second->find(mfName);
it->second->Execute();
}
};
-------------------------------EXE-side example------------------------------------
class BaseEntity
{
public:
DoubleThinkInterface dtInterface;
BaseEntity(){}
virtual ~BaseEntity(){}
};
class Humanoid : public BaseEntity
{
public:
Humanoid(){}
~Humanoid(){}
std::string name;
void Move();
int GetAge(){return 10;}
};
void Humanoid::Move()
{
std::cout << name << ": I'm moving around and such \n";
}
void EndLifeAsWeKnowIt()
{
cout << "Suddenly everything changed... \n";
}
int _tmain(int argc, _TCHAR* argv[])
{
Humanoid *entity = new Humanoid();
entity->name = "Bobby";
entity->dtInterface.AddAction(&EndLifeAsWeKnowIt);
entity->dtInterface.AddActionMF<Humanoid>(entity, &Humanoid::Move, "Move");
entity->dtInterface.Update();
int x; cin >> x;
return 0;
}
-------------------------DLL-side code------------------------------------
DTEntityManager* DTEntityManager::Instance()
{
static DTEntityManager instance;
return &instance;
}
template<class T>
void AddAction(int id, void (*comm)(int, std::string), std::string mfid)
{
DTEntity *ent = DTEntityManager::Instance()->GetEntityFromID(id);
CommandMemberFunction<T> *newcomm = new CommandMemberFunction<T>();
newcomm->comm = comm;
newcomm->entityid = id;
newcomm->mfid = mfid;
ent->SetCommandMF(newcomm);
}
extern "C"
{
DLL_EXPORT void AddEntity(int &idnumber)
{
DTEntity *entity = new DTEntity();
idnumber = entity->ID();
DTEntityManager::Instance()->RegisterEntity(entity);
}
DLL_EXPORT void AddActionToEntity(int id, void (*comm)())
{
DTEntity *ent = DTEntityManager::Instance()->GetEntityFromID(id);
CommandGlobal<void> *newcomm = new CommandGlobal<void>();
newcomm->comm = comm;
ent->SetCommand(newcomm);
}
DLL_EXPORT void AddActionToEntityMF(int id, void (*comm)(int, std::string), std::string mfid)
{
AddAction<void>(id, comm, mfid);
}
DLL_EXPORT void AddActionToEntityMF_int(int id, void (*comm)(int, std::string), std::string mfid)
{
AddAction<int>(id, comm, mfid);
}
}
--------------------------DLL-side Structure for holding callbacks ---------------------------
class CommandBase
{
public:
virtual void Execute() const =0;
};
template<class T>
struct CommandGlobal : CommandBase
{
typedef boost::function<T ()> Command;
Command comm;
virtual T Execute() const
{
return comm();
}
};
template<class T>
struct CommandMemberFunction : CommandBase
{
typedef boost::function<T (int, std::string)> Command;
Command comm;
int entityid;
std::string mfid;
virtual T Execute() const
{
return comm(entityid, mfid);
}
};
At the moment the DLL doesn't compile because of this line:
AddAction<int>(id, comm, mfid);
Because it tries to override
virtual void Execute() const =0;
with a function which returns int. Gives non-covariance error.. I know I have been barking up the wrong tree but I can't see any other solution at the moment either.
Does anyone have any advice on how to do it better? Even if it just a vague direction I should direct my attention in I would appreciate it. Thanks a lot if you bother to read all this!
I think you are complicating too much. See this:
/*************** both ***************/
typedef void (*Prototype1)();
typedef void (*Prototype2)(int);
typedef int (*Prototype3)();
struct FuncList {
Prototype3 func1;
Prototype1 func2;
Prototype1 func3;
Prototype2 func4;
Prototype1 func5;
// ...
};
/*************** dll ***************/
FuncList func_list;
Prototype3 &func1 = func_list.func1;
Prototype1 &func2 = func_list.func2;
Prototype1 &func3 = func_list.func3;
Prototype2 &func4 = func_list.func4;
Prototype1 &func5 = func_list.func5;
/* DLLEXPORT */ void SetFuncList(const FuncList &list) { func_list = list; }
void UsageExample()
{
/* Just call the function */
func2();
}
/*************** exe ***************/
/* declarations (functions must be defined somewhere) */
int func1();
void func2();
void func3();
void func4(int);
void func5();
const FuncList func_list = {
func1,
func2,
func3,
func4,
func5
};
typedef void (*SetFuncListProc)(const FuncList &list);
SetFuncListProc SetFuncList;
void Init()
{
/* ... load the DLL, load "SetFuncList" ... */
SetFuncList(func_list);
}
Quick & dirty answer: pass to Execute a reference to the result type as a void*, and make Execute private. Then wrap Execute in a non-virtual wrapper which returns T by value and does the cast.

How to add/design callback function

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.

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)

C++ Functors and Zero

First a disclaimer, I am replacing a bunch of code which uses boost::function and boost::bind. However, I am moving to a codebase which does not allow rtti. I would like to keep using boost but don't know if there is a way around this restriction.
So, I am trying to mimic some of its functionality, but much more simplified. I have a Callback class:
template <class Class, typename ReturnType = void> class Callback0 {
typedef ReturnType (Class::*Method)();
public:
Callback0(Class* object, Method method)
: m_object(object)
, m_method(method)
{
;
}
Callback0(const Callback0& callback)
: m_object(callback.m_object)
, m_method(callback.m_method)
{
;
}
operator bool() {
return m_object != 0;
}
operator bool() const {
return m_object != 0;
}
ReturnType operator()() {
return (m_object->*m_method)();
}
Callback0<Class, ReturnType>& operator=(const Callback0<Class, ReturnType>& callback) {
if(this != &callback) {
m_object = callback.m_object;
m_method = callback.m_method;
}
return *this;
}
private:
Class* m_object;
Method m_method;
};
This allows me to do simple callbacks with zero parameters:
class Meh {
public:
Meh() {;}
~Meh() {;}
void f0() {
footprint6v("%s\n", __FUNCTION__);
}
};
static void meh() {
Meh* m = new Meh;
Callback0<Meh, void> c0(m, &Meh::f0);
c0();
}
I would like to be able to assign my callback objects to zero as default parameters like so:
class Wtf {
public:
Wtf() : m_callback(0) {;}
~Wtf() {;}
void doSomething(const Callback0<Wtf, void>& callback = 0) {
m_callback = callback;
}
private:
Callback0<Wtf, void> m_callback;
};
This works when using boost::function as you can do:
class Wtf {
public:
Wtf() : m_callback(0) {;}
~Wtf() {;}
void doSomething(const boost::function<void()>& callback = 0) {
m_callback = callback;
}
private:
boost::function<void()> m_callback;
};
I imagine boost is doing some magic here. I know I can just change the parameter to a pointer rather than a reference but as I said, I am replacing a lot of code and would like to minimize the impact of changing from boost.
Boost isn't doing anything magic. 0 is just a NULL function pointer for the function pointer constructor.
I would suggest in your case you just provide a default constructor
Callback0() : m_object(NULL), m_method(NULL) {}
And make doSomething look like
void doSomething(const Callback0<Wtf, void>& callback = Callback0<Wtf, void>()) {