Examples on C++ callbacks for a template class
Hi All,
I've looked around on the net and whilst there are plenty of examples I can't find a page which shows clearly (to me at least) what I need to do to create a callback from my template class to another class.
Basically what I have is a template class which holds generic data structures, and another class which has a specific instance of the template class.
I want to be able to save the data and figured that if I can somehow create a call back from the template class that would work nicly. Just can't figure out how to do it. Any examples/help would be great.
Thanks
Mark
i can't really understand what you want to do.
do you want something like a class that can call any method from any instance of any type?
something like this??:
do you want something like a class that can call any method from any instance of any type?
something like this??:
Callback a,b;b.set(MyInstance,&MyType::MyMethod);// MyInstance is of MyType which can anythinga=b;a();// will call MyInstance.MyMethod();
Sorry for the generic names, but it's hard to give concrete ones without more context.
This is how I'd do it:
The class that wants to have the callback inherits from an interface (Holder<T>::Callbackable), and defines the callback. It can then pass *this into Holder<T>'s constructor as the class instance with the callback.
This is how I'd do it:
#include <string>#include <iostream>template <typename T>class Holder {public: class Callbackable { public: virtual void Callback(const T& t) = 0; }; Holder(const T& t, Callbackable& callback) : t(t), callback(callback) {} void DoCallback() { callback.Callback(t); }private: T t; Callbackable& callback;};class AnotherClass : public Holder<std::string>::Callbackable {public: AnotherClass() : holder("Quack!", *this) {} virtual void Callback(const std::string& t) { std::cout << "AnotherClass::Callback: " << t << "\n"; } void DemoTheCallback() { holder.DoCallback(); }private: Holder<std::string> holder;};int main() { AnotherClass ac; ac.DemoTheCallback();}
The class that wants to have the callback inherits from an interface (Holder<T>::Callbackable), and defines the callback. It can then pass *this into Holder<T>'s constructor as the class instance with the callback.
I have something like:
<code>
template <class T> class map
{
void forEachElement(ProcessMethod pPethod)
{
for (Map::iterator it = m_map.begin(); it != m_map.end(); it++)
{
pMethod(it->second);
}
}
};
</code>
and what I want is to be able to have a instance of map in another class say X, but be able to call forEachElement, passing it a method from X, which will be responsible for the specific processing type.
Thanks
Mark
<code>
template <class T> class map
{
void forEachElement(ProcessMethod pPethod)
{
for (Map::iterator it = m_map.begin(); it != m_map.end(); it++)
{
pMethod(it->second);
}
}
};
</code>
and what I want is to be able to have a instance of map in another class say X, but be able to call forEachElement, passing it a method from X, which will be responsible for the specific processing type.
Thanks
Mark
Try a function pointer.
Alternatively, you could do it like the STL, and pass in a function object.
(I hope you're not rewriting std::map!)
#include <string>#include <iostream>template <typename T>class map {public: map(const T& a, const T& b, const T& c) : a(a), b(b), c(c) {} template <typename C> void forEachElement(C& inst, void (C::*callback)(const T&)) { // example use of callback (inst.*callback)(a); (inst.*callback)(b); (inst.*callback)(c); }private: T a, b, c;};class X {public: X() : m("foo", "bar", "baz") {} void callback(const std::string& t) { std::cout << "X::callback: " << t << "\n"; } void demoTheCallback() { m.forEachElement(*this, &X::callback); }private: map<std::string> m;};int main() { X x; x.demoTheCallback();}
Alternatively, you could do it like the STL, and pass in a function object.
(I hope you're not rewriting std::map!)
Here you go:
Callback.h:
Callback.cpp
Usage:
Callback m;// this object will call any function from any object
m = callback(InstanceOfObject,&TypeOfObject::MethodToCall);// this is how you associate m with an instance and a method
m() or m.exec()// is how you call the method, equivalent with InstanceOfObject->MethodToCall();
It is easy to modify this so that you can call methods with arguments.
Raxvan.
Edit:
your example now is:
Callback.h:
class __iCallback { private: inline __iCallback() { RefCount = 0; } private: virtual void __CallMethod()=0; private: unsigned int RefCount; private: friend class Callback; template <class T> friend class __CallBack; };class Callback { public: Callback(); ~Callback(); Callback(const Callback &other); Callback(__iCallback *prv); public: void operator = (const Callback &other); void operator = (__iCallback *prv); void Detach(); inline bool isEmpty()const { return (method == 0); } public: inline void exec() { if(method) method->__CallMethod(); } inline void operator()() { if(method) method->__CallMethod(); } //------------------------------------------------ private: __iCallback *method; }; //------------------------------------------------ //------------------------------------------------ template <class T> class __CallBack : public __iCallback { private: typedef void (T::*CallProcedure)(); public: __CallBack(T * s ,void (T::*m)()) :source(s),method(m) {} public: virtual void __CallMethod() { (source->*method)(); } private: T * source; CallProcedure method; private: friend class Callback; };//----------------------------------template <typename OBJ> inline __iCallback* callback(OBJ * what, void(OBJ::*method)()) { return new __CallBack<OBJ>(what,&method); }
Callback.cpp
Callback::Callback() : method(0){}Callback::~Callback(){ if(method) { method->RefCount--; if(method->RefCount==0) delete method; }}Callback::Callback(const Callback& other) :method(other.method){ method->RefCount++;}Callback::Callback(__iCallback* prv){ method = prv; method->RefCount++;}void Callback::Detach(){ if(method) { method->RefCount--; if(method->RefCount==0) delete method; } method = 0;}//---------------------------------------------void Callback::operator =(const Callback& other){ if(method) { method->RefCount--; if(method->RefCount==0) delete method; } method = other.method; method->RefCount++;}void Callback::operator = (__iCallback* prv){ if(method) { method->RefCount--; if(method->RefCount==0) delete method; } method = prv; method->RefCount++;}
Usage:
Callback m;// this object will call any function from any object
m = callback(InstanceOfObject,&TypeOfObject::MethodToCall);// this is how you associate m with an instance and a method
m() or m.exec()// is how you call the method, equivalent with InstanceOfObject->MethodToCall();
It is easy to modify this so that you can call methods with arguments.
Raxvan.
Edit:
your example now is:
X yourInstance;pPethod = callback(yourInstance,&X::Method);void forEachElement(Callback pPethod){for (Map::iterator it = m_map.begin(); it != m_map.end(); it++){pMethod(it->second);// suppose that you added support for arguments}}
mattd, I've had a go with your example in my app, getting a compilation error:
error C2784: 'void C3DHashtable<T>::forEachElement(C &,void (__thiscall C::* )(const T & ))' : could not deduce template argument for 'void (__thiscall T1::* )(const T & )' from 'void (__thiscall X::* )(const GridCell &)'
with
[
T=GridCell *
]
and
[
T=GridCell *
]
Can you see where I've got this wrong. An abridged version of my code below (I'm not 100% about the functionality, but is does at least exibit the same compilation problems.
Thanks
Mark
error C2784: 'void C3DHashtable<T>::forEachElement(C &,void (__thiscall C::* )(const T & ))' : could not deduce template argument for 'void (__thiscall T1::* )(const T & )' from 'void (__thiscall X::* )(const GridCell &)'
with
[
T=GridCell *
]
and
[
T=GridCell *
]
Can you see where I've got this wrong. An abridged version of my code below (I'm not 100% about the functionality, but is does at least exibit the same compilation problems.
Thanks
Mark
#include "stdafx.h"#include <string>#include <iostream>#include <map>#include <algorithm>#include <vector>using namespace std;static const C_numberOfDimensions = 3;class C3DHashtableKey { public: C3DHashtableKey(const int iX, const int iY, const int iZ) { m_iCoord[0] = iX; m_iCoord[1] = iY; m_iCoord[2] = iZ; } bool operator<(const C3DHashtableKey & rhs) const { return std::lexicographical_compare(m_iCoord, m_iCoord + C_numberOfDimensions, rhs.m_iCoord, rhs.m_iCoord + C_numberOfDimensions); } /* bool operator==(const C3DHashtableKey & rhs) const { return std::equal_range(m_iCoord, m_iCoord + C_numberOfDimensions, rhs.m_iCoord, rhs.m_iCoord + C_numberOfDimensions); } */ private: int m_iCoord[C_numberOfDimensions]; };template<class T> class C3DHashtable{private: std::map<C3DHashtableKey, T> m_map;public: C3DHashtable(void) { } ~C3DHashtable(void) { } void Insert(const int x, const int y, const int z, T value) { m_map.insert(std::make_pair(C3DHashtableKey(x, y, z), value)); } template <class C> void forEachElement(C& inst, void (C::*callback)(const T&)) { for (std::map<C3DHashtableKey, T>::iterator it = m_map.begin(); it != m_map.end(); it++) { (inst.*callback)(<C3DHashtableKey, T>); } } size_t getNoOfMapElements() { return m_map.size(); } };struct GridCell { // Alternatice constructor for basic setting up of a cell for path finding GridCell( double X, double Y, long Z) { m_X = X; m_Y = Y; m_Z = Z; } double m_X; double m_Y; double m_Z;};template <typename T>class map {public: map(const T& a, const T& b, const T& c) : a(a), b(b), c(c) {} template <typename C> void forEachElement(C& inst, void (C::*callback)(const T&)) { // example use of callback (inst.*callback)(a); (inst.*callback)(b); (inst.*callback)(c); }private: T a, b, c;};class X {public: X() { Map2.Insert(1,2,3, new GridCell(1,2,3)); Map2.Insert(4,5,6, new GridCell(4,5,6)); Map2.Insert(7,8,9, new GridCell(7,8,9)); } //: m("foo", "bar", "baz") {} void callback(const GridCell& t) { } void demoTheCallback() { Map2.forEachElement(*this, &X::callback); }private: C3DHashtable<GridCell*> Map2;};int main() { X x; x.demoTheCallback();}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement