I'm trying to write external draw call optimization, and for that I need to collect hooked calls, store their arguments to analyze them later on.
I've been able to make deferred calls, and somewhat readable arguments, stored in tuple, but I need to read arguments from base class and after thorough googling I can't find anything applicable.
I'll work with array of IDelegateBase mostly, and it would be very inconvenient to convert them to Delegate<...> with full signature, when I mostly would read just one argument. Therefore, I need virtual templated method in IDelegateBase, which would return n-th argument. But virtual templated methods are impossible, so probably I'd have to have templated method in base class, which would call non-template (boost::any?) virtual method and cast it's result, I suppose. But, anyway, I can't get n-th element from tuple via runtime variable.
#include <functional>
#include <iostream>
class IDelegateBase
{
public:
virtual void invoke() { }
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
};
void a() { std::cout << "a called;\n"; }
void b(int x) { std::cout << "b called with " << x << "\n"; }
void c(int x, float y) { std::cout << "c called with " << x << ", " << y << "\n"; }
int main()
{
IDelegateBase* d = new Delegate(a);
d->invoke();
int i = 42;
d = new Delegate(b, i);
d->invoke();
i = 21;
float f = 0.999;
d = new Delegate(c, i, f);
d->invoke();
// I need something like this:
auto test = d->getArgument<float>(1);
};
Update:
Final solution with kind of type checking: https://godbolt.org/z/xeEWTeosx
You could provide a virtual function returning void* and use it in a template, but type safety goes down the drain: Should you ever get the type wrong, you'll end up with undefined behaviour.
For getting element using an index you can use a recursive helper template that compares with one index per recursive call.
class IDelegateBase
{
public:
virtual void invoke() { }
template<class T>
T const& getArgument(size_t index) const
{
return *static_cast<T const*>(getArgumentHelper(index));
}
protected:
virtual void const* getArgumentHelper(size_t index) const = 0;
};
template <typename T, typename... Args>
class Delegate : public IDelegateBase
{
private:
void (*_f)(Args...);
std::tuple<Args...> _args;
public:
Delegate(T& f, Args &...args)
: _f(f), _args(args...) { }
void invoke() final
{
std::apply(_f, _args);
}
protected:
void const* getArgumentHelper(size_t index) const override
{
return GetHelper<0>(index, _args);
}
private:
template<size_t index>
static void const* GetHelper(size_t i, std::tuple<Args...> const& args)
{
if constexpr (sizeof...(Args) > index)
{
if (index == i)
{
return &std::get<index>(args);
}
else
{
return GetHelper<index + 1>(i, args);
}
}
else
{
throw std::runtime_error("index out of bounds");
}
}
};
The use of if constexpr is needed here, since std::get does not compile if a of tuple index out of bounds is used.
Related
I'm trying to implement a Property system in my project similar to Property system in Qt. We just started with some ideas and are in prototyping stage.
Basically, what I understood from Qt is, client should be able to pass the get function, set function and property type through some macro in the .h file. So I tried to mimic the same.
Following is my sample code:
Abstract getter class. This type of getter class is a member in Property Class
class AbstractFunc
{
public:
template < typename R >
R Invoke ()
{
return (this)->Invoke ();
}
};
Get Function template: Return values can be T , T&, const T& , T* etc..
template < typename R, class T > class GetterFunction : public AbstractFunc
{
typedef R (T::*GetterFunc) ();
public:
GetterFunction (T * obj, GetterFunc func):m_Obj (obj), m_Func (func)
{
}
R Invoke ()
{
return m_Obj->*(m_Func) ();
}
public:
T * m_Obj;
GetterFunc m_Func;
};
Property Class:
class Property
{
public:
Property (string name, AbstractFunc* getter):m_name (name), m_getter (getter)
{
}
template < typename R > R GetValue ()
{
return m_getter->Invoke < R > ();
}
private:
string m_name;
AbstractFunc* m_getter;
};
Some Window Class:
class Window
{
public:
};
Example window class
class CheckBox :public Window
{
public:
int GetChecked ()
{
return m_checked;
}
void SetChecked (int nChecked)
{
m_checked = nChecked;
}
void AddProperty (string name)
{
m_prop = new Property (name, new GetterFunction< int, Checked >(this, &Checked::GetChecked));
}
int m_checked;
Property *m_prop;
};
main function:
int main ()
{
CheckBox cc;
cc.AddProperty ("Hello");
cout<<"value:"<< cc.m_prop->GetValue<int>();
return 0;
}
PROBLEM:
Getter function is remembered as AbstractFunc in Property Class. I want to call 'Invoke' on AbstractFunc* instance and it should invoke the member function and return correct return type. The above code throws error at AbstractFunc::Invoke.
see live
Your AbstractFunc isn't abstract at all: its Invoke isn't virtual. So even though GetterFunction also has a method named Invoke, that method doesn't actually override AbstractFunc::Invoke; it just hides it. When you try to call Invoke through the AbstractFunc*, it calls AbstractFunc::Invoke, which goes into infinite recursion and thus produces UB.
I would follow #n.m.'s suggestion to make a class hierarchy like so:
class AbstractFunc {
// lock down construction
AbstractFunc() = default;
public:
template<typename R>
R Invoke();
template<typename R>
bool HasType() const noexcept;
virtual ~AbstractFunc() = default; // need to have SOME virtual method so that we have runtime type info; also a virtual destructor is required anyway
template<typename R>
friend class TypedFunc;
};
template<typename R>
struct TypedFunc : AbstractFunc { // the ONLY instances of AbstractFunc are also instances of specializations of TypedFunc
virtual R InvokeTyped() = 0;
};
// one kind of TypedFunc applies a getter on an object
template<typename R, typename T>
struct GetterFunc : TypedFunc<R> {
// you never see a GetterFunc in the interface anyway... don't see a need to hide these
T *obj; // have you considered std::shared_ptr?
R (T::*getter)();
GetterFunc(T *obj, R (T::*getter)()) : obj(obj), getter(getter) { }
R InvokeTyped() override { return (obj->*getter)(); }
};
template<typename R, typename T>
std::unique_ptr<GetterFunc<R, T>> MakeGetterFunc(T *obj, R (T::*getter)()) {
return std::make_unique<GetterFunc<R, T>>(obj, getter);
}
// another kind applies a functor, etc.
template<typename R, typename F>
struct FunctorFunc : TypedFunc<R> {
F func;
template<typename... G>
FunctorFunc(G&&... args) : func(std::forward<G>(args)...) { }
R InvokeTyped() override { return func(); }
};
This is already usable: if you have an AbstractFunc* or an AbstractFunc&, you can dynamic_cast it down to a TypedFunc of the expected type (e.g. TypedFunc<int>). If that succeeds (you get a nonnull pointer or there is no std::bad_cast exception), then you just call InvokeTyped without having to know what kind of GetterFunc/FunctorFunc/whatever you are actually dealing with. The functions Invoke and HasType declared in AbstractFunc are just sugar to help do this.
template<typename R>
bool AbstractFunc::HasType() const noexcept {
return dynamic_cast<TypedFunc<R> const*>(this);
}
template<typename R>
R AbstractFunc::Invoke() {
return dynamic_cast<TypedFunc<R>&>(*this).InvokeTyped();
// throws std::bad_cast if cast fails
}
Done.
class Property {
std::string name;
std::unique_ptr<AbstractFunc> getter;
public:
Property(std::string name, std::unique_ptr<AbstractFunc> getter) : name(std::move(name)), getter(std::move(getter)) { }
template<typename R>
bool HasType() const noexcept { return getter->HasType<R>(); }
template<typename R>
R GetValue() const { return getter->Invoke<R>(); }
std::string const &GetName() const noexcept { return name; }
};
struct Window {
virtual ~Window() = default;
// doesn't really make sense to add/remove these from outside...
virtual std::vector<Property> GetProperties() = 0;
};
class CheckBox : public Window {
int checked = 0;
public:
int GetChecked() /*const*/ noexcept { return checked; }
void SetChecked(int checked) noexcept { this->checked = checked; }
std::vector<Property> GetProperties() override {
std::vector<Property> ret;
ret.emplace_back("Boxes Checked", MakeGetterFunc(this, &CheckBox::GetChecked));
return ret;
}
};
int main() {
CheckBox cb;
cb.SetChecked(5);
for(auto const &prop : cb.GetProperties()) std::cout << prop.GetName() << ": " << prop.GetValue<int>() << "\n";
}
You could then add e.g. a virtual std::type_info const& GetType() const or similar to AbstractFunc if you want to be able to directly get at the type, etc.
Assume you have a std::tuple with a common base class:
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
How do you iterate over the elements of the tuple at runtime? The usual answer is that you can't because they all have different types, but here I'm happy for a static type of MyBase*. I'm hoping for code like this:
MyTuple t;
for (Base* b : iterate_tuple<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
There are a lot of helpful ideas over at How can you iterate over the elements of an std::tuple?, but they all include the code to run at each iteration in the fiddly template code, whereas I'd like all the fiddly template code bundled into the hypothetical iterate_tuple function so my code is just a normal for loop.
Here's a little wrapper function that gets the tuple value by index, specified at runtime, which does a linear search for the right index by recursively calling itself with a different template parameter. You specify its return type as a template parameter, and the value gets implicitly converted to it.
template <class BaseT, class TupleT, size_t currentIndex = 0>
BaseT* getBasePtr(TupleT& t, size_t desiredIndex) {
if constexpr (currentIndex >= std::tuple_size<TupleT>::value) {
return nullptr;
}
else {
if (desiredIndex == currentIndex) {
return &std::get<currentIndex>(t);
}
else {
return getBasePtr<BaseT, TupleT, currentIndex + 1>(t, desiredIndex);
}
}
}
You can then use it in a loop over the indices of the tuple:
for (size_t i = 0; i < std::tuple_size<MyTuple>::value; ++i) {
MyBase* b = getBasePtr<MyBase>(t, i);
std::cout << "At " << i << " got " << b->getVal() << "\n";
}
It's not quite as neat as a range-based for loop but it's still pretty straightforward to use. (You could wrap it in an iterator class that would support range-based loops but I don't really think it's worth the effort.)
As mentioned and suggested in the question linked to using std::apply is a good way to get each individual element of the tuple.
Making a small helper function to wrap the forwarding of each tuple element makes it easy to use.
It's not the specific for-loop syntax you asked for, but it's as easy to follow if you ask me.
#include <tuple>
#include <utility>
#include <iostream>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1: public MyBase { public: int getVal() override { return 101; } };
class MyFoo2: public MyBase { public: int getVal() override { return 202; } };
using MyTuple = std::tuple<MyFoo1, MyFoo2, MyFoo1>;
template <typename Tuple, typename Callable>
void iterate_tuple(Tuple&& t, Callable c) {
std::apply([&](auto&&... args){ (c(args), ...); }, t);
}
int main() {
MyTuple t;
iterate_tuple(t, [](auto& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
iterate_tuple(t, [](MyBase& arg) {
std::cout << "Got " << arg.getVal() << "\n";
});
}
We can get the exact type by using auto or use the common base type.
As Sam suggests in the comments, it's quite simple to create an array from a tuple.
template<typename Base, typename Tuple, size_t... Is>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple_impl(Tuple& tuple, std::index_sequence<Is...>)
{
return { std::addressof(std::get<Is>(tuple))... };
}
template<typename Base, typename Tuple>
std::array<Base *, std::tuple_size_v<Tuple>> iterate_tuple(Tuple& tuple)
{
return iterate_tuple_impl(tuple, std::make_index_sequence<std::tuple_size_v<Tuple>>{});
}
If you have inheritance, why not to do without tuple and use inheritance capabilities like this:
#include <iostream>
#include <vector>
class MyBase { public: virtual int getVal() = 0; };
class MyFoo1 : public MyBase { public: int getVal() override { return 101; } };
class MyFoo2 : public MyBase { public: int getVal() override { return 202; } };
int main() {
std::vector<std::unique_ptr<MyBase>> base;
base.emplace_back(new MyFoo1);
base.emplace_back(new MyFoo2);
for (auto && derived : base) {
std::cout << derived->getVal() << std::endl;
}
}
I would directly use std::apply, but you can create array of Base*:
template <typename Base, typename Tuple>
std::array<Base*, std::tuple_size<Tuple>> toPtrArray(Tuple& tuple)
{
return std::apply([](auto& ... args){ return std::array<Base*, std::tuple_size<Tuple>>{{&args}}; }, tuple);
}
And then
MyTuple t;
for (Base* b : toPtrArray<MyBase>(t)) {
std::cout << "Got " << b->getVal() << "\n";
}
I want to have a dynamic_call functionality in C++. It should trigger overload resolution and call the most specific function on the target class (Visitor) depending on the dynamic type of the argument. It should replace the visitor pattern and should work like the dynamic keyword in C#.
I pasted what I got so far below. I want to not have to declare the generic lambda on caller side but on the implementation of dynamic call to make it easier to use. Is this possible?
#include <iostream>
struct Base { virtual ~Base() = default; };
class A : public Base {};
class B : public Base {};
template <class... Ts>
class dynamic_call {
public:
template <class F, class Arg>
static void call(F& func, Arg& a) {
call_impl<F, Arg, Ts...>(func, a);
}
private:
template <class F, class Arg>
static void call_impl(F& /*func*/, Arg& /*a*/) {
//end of recursion => nothing more to be done
}
template <class F, class Arg, class T, class... R>
static void call_impl(F& func, Arg& a) {
T* t = dynamic_cast<T*>(&a);
if(t) {
func(*t);
}
call_impl<F, Arg, R...>(func, a);
}
};
using namespace std;
struct Visitor {
void Visit(A&) { cout << "visited for a" << endl; }
void Visit(B&) { cout << "visited for b" << endl; }
};
int main(int /*argc*/, char */*argv*/[])
{
Visitor v;
auto func = [&v](auto& a) { v.Visit(a); };
A a;
dynamic_call<A, B>::call(func, a);
B b;
dynamic_call<A, B>::call(func, b);
{
Base& base(a);
dynamic_call<A, B>::call(func, base);
}
{
Base& base(b);
dynamic_call<A, B>::call(func, base);
}
return 0;
}
I want to call it like this without the need to add the generic lambda.
dynamic_call<A,B>::call(v, a);
Here are some ideas, I am not sure what your requirements are, so they might not fit:
Change Visit into operator(). Then the call syntax reduces to dynamic_call<A,B>::call(v, a); as you required. Of course that is only possible if the interface of the visitor may be changed.
Change func(*t) in call_impl to func.Visit(*t). Then again the caller can use dynamic_call<A,B>::call(v, a); and no change to the interface of the visitor is necessary. However every visitor used with dynamic_call now needs to define Visit as visitor method. I think operator() is cleaner and follows the usual patterns, e.g. for Predicates in the standard library more.
I don't particularly like either of these because the caller always has to know the possible overloads available in the visitor and has to remember using dynamic_call. So I propose to solve everything in the visitor struct:
struct Visitor {
void Visit(A&) {
cout << "visited for a" << endl;
}
void Visit(B&) {
cout << "visited for b" << endl;
}
void Visit(Base& x) {
dynamic_call<A,B>::call([this](auto& x){Visit(x);}, x);
}
};
This can be called with v.Visit(a), v.Visit(b) and v.Visit(base). This way the user of Visitor does not need to know anything about the varying behavior for different derived classes.
If you do not want to modify Visitor, then you can just add the overload via inheritance:
struct DynamicVisitor : Visitor {
void Visit(Base& x) {
dynamic_call<A,B>::call([this](auto& x){Visit(x);}, x);
}
};
The points can be combined, for example into:
struct Visitor {
void operator()(A&) {
cout << "visited for a" << endl;
}
void operator()(B&) {
cout << "visited for b" << endl;
}
void operator()(Base& x) {
dynamic_call<A,B>::call(*this, x);
}
};
Used as v(a), v(b) and v(base).
I have written a small piece of code where I am able to call setter and getter functions packed within a functoid using mem_fun templates.
I now would like to use this approach on top of a class hierarchy where every class might have getter and setter which can be registered as pair within a vector or array to be able to call the getter and setter if needed. GUIObject and GUICompositeObject are example classes out of the described class hierarchy.
The bound_mem_fun_t for the objects have unfortunately different types and thats the reason I don't know how to integrate them into an array/vector of pointers to the functors.
In c++11 I would use std::function. Is there a way to emulate this in c++98?
Because our compiler support only c++98 I cannot use the new features of c++11 or c++14. Also boost is not allowed.
#include <functional>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
template<typename T>
struct bound_mem_fun_t
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
int operator()() { return m_GetFunc(obj); } ;
void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
GUIObjectFunc(17);
int ii = GUIObjectFunc();
bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
GUICompObjectFunc(17);
int iChilds = GUICompObjectFunc();
return 0;
}
Here is the complete solution after #filmors answer:
#include <functional>
#include <vector>
#include <iostream>
class GUIObject
{
int m_Alpha;
public:
void SetAlpha(int a) { m_Alpha = a;};
int GetAlpha() {return m_Alpha;};
};
class GUICompositeObject: public GUIObject
{
int m_NumOfChilds;
public:
void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
int GetNumOfChilds() {return m_NumOfChilds;};
};
struct bound_mem_fun_base
{
virtual int operator()() =0;
virtual void operator()(int) =0;
};
template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{
bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
virtual int operator()() { return m_GetFunc(obj); } ;
virtual void operator()(int i) { m_SetFunc(obj, i); } ;
std::mem_fun_t<int, T> m_GetFunc;
std::mem_fun1_t<void, T, int> m_SetFunc;
T* obj;
};
template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}
int main()
{
GUIObject kGUIObject;
GUICompositeObject kCompObj;
std::vector<bound_mem_fun_base*> kBoundVector;
kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
for (int i = 0; i < 4 ; i++)
{
(*kBoundVector[i])(i*10);
int res = (*kBoundVector[i])();
std::cout << "Getter result " << res << "\n";
}
return 0;
}
Unfortunately the make_setter function does not really shorten the creation of the functor. Any ideas will be welcome.
Just give your bound_mem_fun_t<T> a common base class and use dynamic dispatch to solve your problem:
struct bound_mem_fun_base {
virtual int operator()() = 0;
virtual void operator()(int) = 0;
};
template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...
Then you can keep pointers to bound_mem_fun_base in your vector and call the elements as (*v[0])().
Also, TR1 does contain std::tr1::function, is that available?
First a remark on std::function from c++11: That will not solve your problem, because you need an already bounded function pointer. This pointer must be bound to your object. I believe what you need is an own implementation to std::bind.
I started only a very! small Binder class which is hopefully a starting point for your needs. If you need to have template parameter lists in older c++ versions, take a look for loki. http://loki-lib.sourceforge.net/
As a hint I can give you a short example of what i did:
class A
{
private:
int val;
public:
A(int i): val(i) {}
void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};
class B
{
private:
int val;
public:
B(int i): val(i){}
void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};
class Base
{
public:
virtual void operator()(int i)=0;
};
template <typename T>
class Binder: public Base
{
void (T::*fnct)(int);
T* obj;
public:
Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}
void operator()(int i)
{
(obj->*fnct)(i);
}
};
int main()
{
A a(100);
B b(200);
// c++11 usage for this example
//std::function<void(int)> af= std::bind( &A::Do, &a, std::placeholders::_1);
//af(1);
// hand crafted solution
Base* actions[2];
actions[0]= new Binder<A>( &A::Do, &a);
actions[1]= new Binder<B>( &B::Go, &b);
actions[0]->operator()(55);
actions[1]->operator()(77);
}
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)