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;
}
}
Related
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();
}
I have a problem with the following piece of code that can't even compile.
The problem is on the line
class2_ = new Class2(myFunction);
In fact, I don't now how to reference myFunction, I have also tried class2_ = new Class2(&Class3::myFunction); but the compiler still complains :(
2 constraints:
The function myFunction can't be declared as static
This code will be used in a Arduino base project, I can't use boost::bind
Could you please help me ?
Thanks.
class Class2 {
typedef void(*MyFunction) (int what);
MyFunction fn_;
public:
Class2(MyFunction fn) : fn_(fn) {}
void invoke(int val) {
fn_(val);
}
};
class Class3 {
Class2* class2_;
public:
Class3() {
class2_ = new Class2(myFunction);
class2_->invoke(12);
}
void myFunction(int what) {
// Do some work
}
};
void test2() {
Class3 instance3;
}
How about using an interface for that:
class ClassWithFunction {
public:
virtual void myFunction(int what) = 0;
}
class Class2 {
ClassWithFunction* fn_;
public:
Class2(MyFunction* fn) : fn_(fn) {}
void invoke(int val) {
fn_->myFunction(val);
}
};
class Class3 : ClassWithFunction {
Class2* class2_;
public:
Class3() {
class2_ = new Class2(this);
class2_->invoke(12);
}
void myFunction(int what) {
// Do some work
}
};
You need to use pointer to member function.
class Class3;
class Class2 {
typedef void(Class3::*MyFunction) (int);
MyFunction fn_;
public:
Class2(MyFunction fn) : fn_(fn) {}
void invoke(Class3 *p, int val) {
(p->*fn_)(val);
}
};
class Class3 {
Class2* class2_;
public:
Class3() {
class2_ = new Class2(&Class3::myFunction);
class2_->invoke(this, 12);
}
void myFunction(int what) {
// Do some work
}
};
If you want that Class2 accepts any callable object with signature void(int), then class template, function wrapper, lambda expression etc. will help.
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 have a class which needs more callbacks..
I am trying to implement them with an interface:
class CallbacksInterface
{
public:
virtual bool mycallback1() = 0;
virtual bool mycallback2() = 0;
virtual bool mycallback3() = 0;
};
Class BusImplementation{
public:
addRequest(bool (CallbacksInterface::*callback)());
}
Callback is parameter for addRequest() method and is defined as pointer to interface method.
So I want to add request..
//class with callbacks
class Main:CallbacksInterface{
public:
bool mycallback1(){..};
bool mycallback2(){..};
bool mycallback3(){..};
//..
}
BusImplemantation bus;
Main main;
bus.addRequest(main.mycallback1);
bus.addRequest(main.mycallback2);
bus.addRequest(main.mycallback3);
But I cant pass a callback into my BusImplemantation class
error: argument of type 'bool (Main::)()' does not match 'bool (CallbacksInterface::*)()'
I think there is a solution with templates, but I am programming embedded devices and my compiler is limited.
A simpler approach would be to define a single interface type representing a function:
struct ICallback
{
virtual bool operator()() const = 0;
};
and implement it as many times as necessary:
struct Foo : ICallback
{
virtual bool operator()() const { return true;}
};
struct Bar : ICallback
{
virtual bool operator()() const { return false;}
};
then your bus implementation can take callback interfaces:
class BusImplemantation{
public:
void addRequest(const ICallback* callback) { .... }
};
then
BusImplemantation bus;
Foo foo; // can be called: bool b = foo();
Bar bar; // can be called: bool b = bar();
bus.addRequest(&foo);
bus.addRequest(&bar);
You could also investigate using std::function and avoiding the common interface altogether.
I also strongly suggest going with an abstract interface. However, if you really want the original approach for some reason, you need something like this:
void addRequest(bool (CallbacksInterface::*callback)(), CallbacksInterface* pTarget) {...}
...
bus.addRequest(&CallbacksInterface::mycallback1, &main);
// ! Not &Main::mycallback1 - that wouldn't compile
...
// calling a callback
(pTarget->*callback)();