I want to register a callback handler (method) of the one class (Y) in another (X). I can't use std::function because of possible heap allocation and I must have an access to members of a class that registers the handler. I also want to avoid static functions.
I've came up with some workaournd but got stuck on calling the callback:
template<class T>
using clbkType = void(T::*)(void);
template<class T>
class X
{
public:
void registerClbck(clbkType<T> clbk) {
callback = clbk;
}
void call() {
callback(); // ERROR C2064: term does not evaluate to a function taking 0 arguments.
//(((X<T>*)this)->X<T>::callback)(); // same error
}
private:
clbkType<T> callback;
};
class Y
{
public:
Y() {
x.registerClbck(&Y::handler);
}
// just for a test: fire a callback in class X
void fire() {
x.call();
}
int getA() { return a; }
private:
int a{ 0 };
X<Y> x{};
void handler() {
a = 5;
}
};
int main()
{
Y y;
y.fire();
return y.getA();
}
link to code: https://godbolt.org/z/PhY41xsWE
PS. I'm not sure if this is a safe solution, so please put any comment on that.
Thanks!
The member function pointer needs a specific class object to invoke, so you need to do this:
template<class T>
class X
{
public:
// ...
void call(T& obj) {
(obj.*callback)();
}
// ...
};
class Y
{
public:
// just for a test: fire a callback in class X
void fire() {
x.call(*this);
}
// ...
};
Demo.
The member function pointer need an instance to be called on.
If you want to bind the instance, here is a possible way to implement it.
template<typename T>
struct member_callback {
T* instance;
void(T::*callback)();
void operator()(){(instance->*callback)();}
};
template<typename T>
struct X{
void registerClbck(member_callback<T> clbk) { callback = clbk; }
void call() { callback(); }
member_callback<T> callback;
};
struct Y{
public:
Y() { x.registerClbck({this,&Y::handler}); }
void fire() { x.call(); }
int getA() { return a; }
private:
int a{ 0 };
X<Y> x{};
void handler(){ a = 5; }
};
int main()
{
Y y;
y.fire();
return y.getA();
}
Related
Say I have this class:
class Object {
public:
int x;
int y;
void update(SDL_Event);
void start();
};
I want to be able to make start and update change behavior from instance to instance.
I have tried using function pointers, like so:
class Object {
public:
int x;
int y;
void (*update)(SDL_Event);
void (*start)(void);
};
void teststart() {
x++;
return;
}
And in my main(), I do:
testlevel.objs[1].start = teststart;
But then, I cannot reference variables from inside the class.
I am sure there is something obvious I am overlooking, but searching online yields no results for when the pointer is in the class.
Maybe function pointers are not the right answer?
You would need to pass your functions a pointer/reference to the Object instance, eg:
class Object {
public:
int x;
int y;
void (*doupdate)(Object*, SDL_Event);
void (*dostart)(Object*);
void update(SDL_Event event) { if (doupdate) doupdate(this, event); }
void start() { if (dostart) dostart(this); }
};
void teststart(Object* obj) {
obj->x++;
}
void testupdate(Object* obj, SDL_Event event) {
// update obj as needed...
}
Object &obj = testlevel.objs[1];
obj.dostart = teststart;
obj.doupdate = testupdate;
Otherwise, use std::function with capturing lambdas instead:
#include <functional>
class Object {
public:
int x;
int y;
std::function<void(SDL_Event)> update;
std::function<void()> start;
};
Object *obj = &(testlevel.objs[1]);
obj->start = [obj](){
obj->x++;
};
obj->update = [obj](SDL_Event event){
// update obj as needed...
};
Given a class:
class myClass{
// ...
private:
int helperFuncForA();
int secondhelperFuncForA();
public:
void A();
// ...
};
Suppose that the helper functions are not used outside of A; how do I encapsulate them such that calling them outside of A is impossible? Do I do:
class myClass{
// ...
public:
class {
private:
int helperFuncForA();
int secondhelperFuncForA();
public:
void call();
} A;
// ...
};
and then call by writing:
myClass obj;
obj.A.call();
? Perhaps, I could overload A's () operator instead of making the call() function for convenience. What is the correct way?
The correct way is using of lambdas:
class myClass{
// ...
private:
// remove from here
//int helperFuncForA();
//int secondhelperFuncForA();
public:
void A();
// ...
};
// somewhere
void myClass::A()
{
auto helperFuncForA = [this]() -> int
{
//...
return 1;
};
auto secondhelperFuncForA = [this]() -> int
{
//...
return 2;
};
//...
int x = helperFuncForA();
x += secondhelperFuncForA();
}
If some method can only be used by in the function void A(), you probably need a class.
But you can do something like this if you want :
#include <iostream>
class ClassTest
{
public:
struct A{
private:
void helperFunc() {
std::cout << "Executing Helper Func " << std::endl;
}
public:
void operator() (){
helperFunc();
}
};
A a;
void classFunc(){
//a.helperFunc(); <- Impossible helperFunc private
a();
}
};
int main()
{
ClassTest c;
c.classFunc();// Print : Executing Helper Func
//OR
c.a();// Print e: Executing Helper Func
}
I was able to make the callback work without class templates. But my requirement is to implement callbacks with passing class objects which are in template form. I have written my intent in the main(), but somehow I am unable to make it work.
I cannot use boost and C++11 for my current issue. Any help would be greatly appreciated.
// TestProj.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "glb.h"
#include "Test.h"
#include <iostream>
using namespace std;
class MyCallBack
{
private:
class Callback
{
public:
virtual ~Callback() { }
virtual void call() = 0;
};
template <typename T>
class ClassCallback : public Callback
{
private:
T* object;
void (T::*callback)();
public:
ClassCallback(T* obj, void (T::*clbk)()) : object(obj), callback(clbk) {}
virtual void call() { (object->*callback)(); }
};
private:
Callback* callback;
public:
MyCallBack() : callback(NULL) { }
~MyCallBack() { delete callback; }
template <typename T>
MyCallBack(T* obj, void (T::*clbk)())
{
callback = new ClassCallback<T>(obj,clbk);
}
void operator () ()
{
callback->call();
}
};
typedef enum {
EVENT1 = 1,
EVENT2 = 2,
EVENT3 = 4,
EVENT4 = 8
} MyEvent_t;
template <class EventT>
class EventHandler
{
public:
virtual void on_event(EventT _event) = 0;
};
class MyHandler:public EventHandler<MyEvent_t>{
virtual void on_event(MyEvent_t _event){
switch(_event){
case EVENT1:
break;
case EVENT2:
break;
}
}
};
int _tmain(int argc, _TCHAR* argv[])
{
EventHandler<MyEvent_t> *my_handler = new MyHandler();
MyCallBack rcb(my_handler,&MyHandler<MyEvent_t>::on_event);
// to check the callback
rcb();
return 0;
}
Thanks a lot of any leads!!!
The line
MyCallBack rcb(my_handler,&MyHandler<MyEvent_t>::on_event);
is a problem since on_event takes an argument. The member function pointer expected in the constructor of MyCallBack() does not take any arguments.
The following works for me from a compile/build point of view. You'll have to figure out how to make it work for a semantic point of view.
#include <iostream>
using namespace std;
class MyCallBack
{
private:
class Callback
{
public:
virtual ~Callback() { }
virtual void call() = 0;
};
template <typename T>
class ClassCallback : public Callback
{
private:
T* object;
void (T::*callback)();
public:
ClassCallback(T* obj, void (T::*clbk)()) : object(obj), callback(clbk) {}
virtual void call() { (object->*callback)(); }
};
private:
Callback* callback;
public:
MyCallBack() : callback(NULL) { }
~MyCallBack() { delete callback; }
template <typename T>
MyCallBack(T* obj, void (T::*clbk)())
{
callback = new ClassCallback<T>(obj,clbk);
}
void operator () ()
{
callback->call();
}
};
typedef enum {
EVENT1 = 1,
EVENT2 = 2,
EVENT3 = 4,
EVENT4 = 8
} MyEvent_t;
template <class EventT>
class EventHandler
{
public:
void event() { on_event(EventT()); }
virtual void on_event(EventT _event) = 0;
};
class MyHandler:public EventHandler<MyEvent_t>{
virtual void on_event(MyEvent_t _event){
switch(_event){
case EVENT1:
break;
case EVENT2:
break;
default:
break;
}
}
};
int main(int argc, char* argv[])
{
EventHandler<MyEvent_t> *my_handler = new MyHandler();
MyCallBack rcb(my_handler,&EventHandler<MyEvent_t>::event);
// to check the callback
rcb();
return 0;
}
I think what you are trying to achive is the action pattern.
Have a look here: https://en.wikipedia.org/wiki/Command_pattern
And now to the implementation:
#include <iostream>
#include <memory>
struct Action {
virtual void execute() = 0;
};
struct SomeAction : public Action {
void execute() {
std::cout << "SomeAction" << std::endl;
}
};
struct SomeOtherAction : public Action {
void execute() {
std::cout << "SomeOtherAction" << std::endl;
}
};
class EventHandler {
std::unique_ptr<Action> action; // The unique ptr will delete action if the event handler is destroyed
public:
EventHandler() :
action(new SomeAction())
{
}
void setAction(Action* newAction) {
action = std::unique_ptr<Action>(newAction);
}
void eventCalled() {
// This function is invoked from the outside if the event happens
action->execute();
}
};
int main() {
EventHandler eventHandler;
//Some event is called
eventHandler.eventCalled(); // Output "SomeAction"
// We change the action later in time
eventHandler.setAction(new SomeOtherAction());
// Another Event gets called
eventHandler.eventCalled(); // Output "SomeOtherAction"
return 0;
}
class Foo {
public:
void methodA();
};
class ManagedFoo {
Foo fooInst;
public:
void methodA() { doSomething(); fooInst.methodA();}
};
Now I want to make ManagedFoo as a template, managing any class not only Foo, and before any of Foo's function is called, call doSomething first.
template<typename _TyManaged>
class Manager {
_TyManaged _managedInst;
void doSomething();
public:
/*Forward every function called by _managedInst*/
/*How to write this?*/
};
I want to make it the same, make it replaceable between this two class, like this :
Foo* foo = new Foo();
foo->methodA();
Manager<Foo> managedFoo = new Manager<Foo>();
managedFoo->methodA(); //Hope it call Manager::doSomething() first then call _managedInst.methodA();
Can C++11 template do such thing? if answer is yes, how to?
Solution based on operator-> overloading:
#include <iostream>
#include <memory>
class A {
public:
void foo() { std::cout << "foo\n"; }
void bar() { std::cout << "bar\n"; }
};
template <typename T>
class ManagedBase {
std::shared_ptr<T> _inst;
public:
ManagedBase(const std::shared_ptr<T> inst) : _inst(inst) { }
virtual ~ManagedBase() { }
std::shared_ptr<T> operator->() {
before();
return this->_inst;
}
virtual void before() =0;
};
template <typename T>
class ManagedPrint : public ManagedBase<T> {
public:
ManagedPrint(const std::shared_ptr<T> inst) : ManagedBase(inst) { }
virtual void before() {
std::cout << "Said: ";
}
};
int main() {
auto ma = ManagedPrint<A>(std::make_shared<A>());
ma->bar(); // Said: foo
ma->bar(); // Said: bar
}
Something like this?
template<typename _TyManaged>
class Manager {
_TyManaged _managedInst;
void doSomething();
public:
_TyManaged* operator->() {
doSomething();
return &_managedInst;
}
};
This can solve your problem. But I'm still not sure what you want to do with your Manager class.
class Foo {
public:
void methodA();
};
template<typename T>
class ManagedFoo : public T {
public:
// some further extensions
};
And of course in this way you change the semantic of the Foo class by the manager from:
It has a
to
It is a
So I'm not sure if this is true in your case.
I've implemented my callbacks with interface..
struct ICallback
{
virtual bool operator()() const = 0;
};
and function for adding a callback
void addCallback(const ICallback* callback) { .... }
and use, callback is in some class
class BusImplemantation{
public:
struct Foo : ICallback
{
virtual bool operator()() const { return true;}
}foo;
void OtherMethod();
int OtherMember;
};
But because callback is class(not function/method), I cant within callback access to OtherMethod and OtherMember. If callback would be not class, but only method than it would be possible.(inner class vs. method)
I cant pass OtherMethod and OtherMember to callback as parameters.
Is there any better solution for that? maybe with templates?
Use std::function:
void addCallback(const std::function<bool()>) { .... }
class BusImplemantation{
public:
bool Callback() { return true; }
void OtherMethod();
int OtherMember;
};
BusImplemantation obj;
addCallback(std::bind(&BusImplemantation::Callback, obj));
Check out boost::bind for a bunch of alternatives on how to implement this.
Could you do something like this instead:
typedef std::function<bool()> CallbackFunc;
void addCallback(const CallbackFunc callback) { .... }
class BusImplemantation{
public:
struct Foo
{
Foo(member) : OtherMember(member) { }
bool operator()() const { return true; }
void OtherMethod();
int OtherMember;
}foo;
};
Instead of making your callback an interface, make it use std::function to make it a function object (a Functor), and any extra data or methods that your functor needs can be a part of the functor class.
The whole point of using callback objects instead of free functions is that you can associate arbitrary state with them:
class BusImplemantation{
public:
struct Foo : ICallback
{
explicit Foo(BusImplementation &p) : parent(p) {}
virtual bool operator()() const;
private:
BusImplementation &parent;
} foo;
BusImplementation() : foo(*this)
{
addCallback(&foo)
}
void OtherMethod();
int OtherMember;
};
bool BusImplementation::Foo::operator() () const
{
if (parent.OtherMember == 0) {
parent.OtherMethod();
return false;
}
return true;
}
I think your ICallback interface must have pointer to controlled class with base interface, assume it BusImplemantation and inside callback use this pointer.
struct ICallback
{
virtual bool operator()() const = 0;
void setControlObject(BusImplemantation* o)
{
obj = o;
}
BusImplemantation* obj;
};
class BusImplemantation
{
public:
void addCallback(const ICallback* callback)
{
callback->setControlObject(this);
}
void OtherMethod();
int OtherMember;
};
And use:
class SomeCb : ICallback
{
bool operator()
{
obj->OtherMethod();
return true;
}
}