Im working on a GUI and i want to be able to pass function pointers to my buttons, however, these could be called from different kinds of classes, which is why i made it use templates.
I do believe it stores the function pointer correctly but i cannot call it correctly.
class MainMenuScene: public Scene
{
public:
void add_button(){
void (MainMenuScene::*func)();
func = &MainMenuScene::test;
Button b(func);
b.click();
}
void test();
private:
GUI<MainMenuScene> gui;
};
template<class T>
class Button: public GUI_object{
public:
Button(void (T::*func)());
void click(){
func_();
private:
void (T::*func_)();
};
This is the error i get:
Button.h|23|error: must use '.*' or '->*' to call pointer-to-member function
in '((Button<MainMenuScene>*)this)->Button<MainMenuScene>::func_ (...)',
e.g. '(... ->* ((Button<MainMenuScene>*)this)->Button<MainMenuScene>::func_) (...)'|
The function that you store a pointer to is not a static function so you need an object instance to call it.
Something like this maybe:
class MainMenuScene: public Scene
{
public:
void add_button(){
void (MainMenuScene::*func)();
func = &MainMenuScene::test;
Button<MainMenuScene> b(this, func);
b.click();
}
void test();
private:
GUI<MainMenuScene> gui;
};
template<class T>
class Button: public GUI_object{
public:
Button(T* obj, void (T::*func)());
void click(){
(obj_->*func_)(); }
private:
void (T::*func_)();
T* obj_;
};
A member function pointer must be used on a specific object. For example, in your case you would need a MainMenuScene object on which to call your function pointer.
Example:
class MainMenuScene
{
public:
void test() {
std::cout << "Hello!" << std::endl;
}
};
int main()
{
void (MainMenuScene::*myPointerToMember)() = &MainMenuScene::test;
MainMenuScene myObj{};
MainMenuScene* myObjP = &myObj;
(myObj.*myPointerToMember)(); //Parentheses around (myObj.*myPointerToMember) are important
(myObjP->*myPointerToMember)();
}
Related
I have this map:
map<IEvent, EventHandler, IEventCompare>
Where EventHandler is defined as typedef void (*EventHandler)(IEvent);
IEvent is a class that describes a general event.
Now I want to add to this map a function that receives CreationEvent, a class that inherits IEvent. The function is defined so:
void onCreate(CreationEvent);
But when I try to add it to the map, I get a compilation error
E0167 argument of type "void (Engine::IObject::*)(Engine::CreationEvent)" is incompatible with parameter of type "Engine::EventHandler"
And if I try to explicitly convert it to EventHandler:
E0171 invalid type conversion
I can declare onCreate with IEvent, but I would like to avoid it since it will require me to assume the type of event, and it is not well defined.
Is there a way to do what I try?
IEvent:
/**
* Represents an Event, such as collision between 2 objects or click on an object.
*/
class IEvent
{
public:
IEvent(string name) { this->name = name; };
/**
* Copy constructor.
*/
IEvent(const IEvent& other) { this->name = other.name;};
string getName() const { return this->name; };
protected:
string name;
};
CreationEvent:
class CreationEvent : public IEvent
{
public:
CreationEvent();
std::chrono::time_point<std::chrono::system_clock> getCreateTime() const;
private:
std::chrono::time_point<std::chrono::system_clock> creationTime; /**< The creation time of this event.*/
};
Notes:
Everything is inside namespace Engine, and the map is declared inside IObject.
If I get your idea right, you want:
Have typed events with base event class.
Have handlers with base handler class.
Handlers can receive event of certain type.
Consider the next example. For the simplicity I used std::vector instead of std::map, and put it inside event class.
This code contains ugliness, leaks and must not be used in a "production" without modifications.
#include <iostream>
#include <vector>
//***********************************************************//
struct event;
struct handler
{
};
struct event_handler
{
event_handler(handler* receiver) : receiver_{ receiver } {}
handler* receiver_;
virtual void invoke(event& evt) = 0;
};
template <typename T, typename U>
struct event_handler_impl : event_handler
{
typedef void (T::* handler_function)(U&);
event_handler_impl(handler* receiver, handler_function function) :
event_handler{ receiver_ },
function_{ function } {}
void invoke(event& evt) {
T* typed_receiver = static_cast<T*>(receiver_);
U& typed_event = static_cast<U&>(evt);
(typed_receiver->*function_)(typed_event);
}
handler_function function_;
};
struct event
{
void subscribe(event_handler* hdlr)
{
//TODO: Check. Is double added?
handlers_.push_back(hdlr);
}
void sent()
{
for (auto& item : handlers_)
{
item->invoke(*this);
}
}
std::vector<event_handler*> handlers_;
};
//*****************************EXAMPLE***********************//
struct creation_event : public event
{
int creation_id{};
};
struct bar_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "bar" << evt.creation_id << std::endl;
}
};
struct foo_handler : public handler
{
void handle_creation(creation_event& evt)
{
std::cout << "foo" << evt.creation_id << std::endl;
}
};
template<typename T, typename U>
void subscribe_to_event(U& evt, T* reciver, void (T::* handler_function)(U&))
{
evt.subscribe(new event_handler_impl<T, U>(reciver, handler_function));
}
int main()
{
creation_event evt;
bar_handler bar;
foo_handler foo;
subscribe_to_event(evt, &foo, &foo_handler::handle_creation);
subscribe_to_event(evt, &bar, &bar_handler::handle_creation);
evt.sent();
evt.creation_id = 1;
evt.sent();
return 0;
}
The only tricky part is:
template <typename T, typename U>
struct event_handler_impl : event_handler
Here we generating classes for storing our typed “callback” and using polymorphism to store those classes inside our std::vector since they are all child classes for handler.
As a suggestion - consider using smart pointers instead of raw pointers. Also you can put function void subscribe_to_even(…) to the handler base class, so you can remove second parameter and just pass "this" to the event_handler_impl - new event_handler_impl<T, U>(this, handler_function)
Is it somehow possible to store the class from a template without making the the whole class a template?
Task:
I have two functions, v1 without parameters and v2 with parameters,
If v1 was called somewhere nothing happens with Use(), if v2 was called somewhere Use() should execute a function_ptr with the instance I got from DoSometh(T*).
e.g.
class MyClass
{
//v1 no parameters
void DoSomething()
{
}
//v2 with parameter
template<class T>
void DoSomething(T* instance, void (T::*func)())
{
store somewhere?? = instance;
}
void Use()
{
//if DoSometh(T* instance) was used before
if(instance != NULL)
{
(*instance->)//call function pointer from DoSomething(T*,void (T::*)())
}
}
}
std::function problem
update:
class Timer : public ITickable
{
std::function<void()> test; //adding this does weird things
virtual void Tick() {}
}
class MyClass
{
ITickable* tickable_;
void Tick()
{
tickable_->Tick(); //let's assume it points to a Timer obj.
}
}
I think std::function and std::bind (C++11) do accomplish what you want, as already suggested in the comments. A simplified mock-up of your Timer class could be:
class Timer
{
std::function<void()> m_task;
public:
template <typename T>
void setTask(T &instance, void (T::*fcn)()) // consider T const & if applicable
{
m_task = std::bind(fcn, &instance);
}
void fire()
{
if (m_task) // std::function overloads operator bool()
m_task();
}
};
When setTask is called with an object and a member-function that can be called on this object, a std::function object is created (you could choose to do this in a constructor of course). When the timer fires, this object is checked (using operator bool(), provided by std::function), and if it is callable (e.g. when setTask() has been called before), it calls the function.
For example:
class MyClass
{
public:
void func()
{
std::cout << "Hi from MyClass\n";
}
};
class MyOtherClass
{
public:
void func()
{
std::cout << "Hi from MyOtherClass\n";
}
};
int main(int argc, char **argv)
{
MyClass x1;
MyOtherClass x2;
Timer t1, t2;
t1.setTask(x1, &MyClass::func);
t2.setTask(x2, &MyOtherClass::func);
t1.fire();
t2.fire();
}
I have 2 class, I would like to pass a method from one to other by callback!
See that I also wish to hold the address of this method using void (*callBack)();
I'm used to do this in C, but I dont know how to do this in c++;
#include <iostream>
using namespace std;
class A
{
private:
void (*callBack)(); //to hold the address of the method
public:
A();
void setCallBack(void(*cB)());
void useCallBack();
};
A::A()
{
}
void A::setCallBack(void(*cB)())
{
callBack = cB;
}
void A::useCallBack()
{
callBack();
}
class B
{
private:
A * Aguy;
public:
B();
void someMethod();
void otherMethod();
};
B::B()
{
Aguy = new A();
}
void B::otherMethod()
{
Aguy->setCallBack(someMethod);
Aguy->useCallBack()
}
void B::someMethod()
{
cout << "Hello. I'm from class b" << endl;
}
int main()
{
B Bguy;
Bguy.otherMethod();
return 0;
}
The problem is that:
void (*callBack)();
This is not a pointer to a method. This is a pointer to a function.
To have a pointer to a method you need to specify the class the method is in.
void (B::*callBack)();
Then when you call it you need to call it via an object.
void A::useCallBack(B* b)
{
(b->*callBack)();
}
But this is probably not what you want.
What you really want is a wrapper that encapsulates all this.
I would take a look at std::function. This will allow you to wrap a method call and an object into a single object that you can then call.
std::function<void()> callback;
Just replace all your occurrences of void(*cB)() with std::function<void()> then you can bind an instance of the object to the method at the call point.
Aguy->setCallBack(std::bind(&B::someMethod, this));
This also allows you to seemly pass any normal function or functor as a callback.
void print()
{ std:cout << "It worked\n";
}
...
Aguy->setCallBack(&print);
struct Printer
{
void operator()() const
{
std::cout << "It worked with obejct\n";
}
}
...
Aguy->setCallBack(Printer());
If you need to pass member function pointers see the modified code. it uses modern c++ constructs.
#include <iostream>
#include <functional>
using namespace std;
class A
{
private:
typedef std::function<void()> some_void_function_type;
some_void_function_type f_;
public:
A();
void setCallBack(some_void_function_type f);
void useCallBack();
};
A::A()
{
}
void A::setCallBack(some_void_function_type f)
{
f_ = f;
}
void A::useCallBack()
{
f_();
}
class B
{
private:
A * Aguy;
public:
B();
void someMethod();
void otherMethod();
};
B::B()
{
Aguy = new A();
}
void B::otherMethod()
{
Aguy->setCallBack(std::bind(&B::someMethod, this));
Aguy->useCallBack();
}
void B::someMethod()
{
cout << "Hello. I'm from class b" << endl;
}
int main()
{
B Bguy;
Bguy.otherMethod();
return 0;
}
See c++ - <unresolved overloaded function type> for details.
To quote the answer:
In C++, member functions have an implicit parameter which points to
the object (the this pointer inside the member function). Normal C
functions can be thought of as having a different calling convention
from member functions, so the types of their pointers
(pointer-to-member-function vs pointer-to-function) are different and
incompatible. C++ introduces a new type of pointer, called a
pointer-to-member, which can be invoked only by providing an object.
Put static on someMethod:
class B
{
private:
A * Aguy;
public:
B();
static void someMethod();
void otherMethod();
};
void B::otherMethod() {
Aguy->setCallBack(B::someMethod);
Aguy->useCallBack(); // adding missing semicolon
}
Basically, I need to set a variable outside of the constructor and make it accessible to the entire class.
It would need to work something like this:
#include <iostream>
#include <string>
template <typename MT>
class CallbackFunction
{
void (*func)(MT);
MT *data;
public:
void SetCallbackData (void (*f)(MT), MT *d)
{
func = f;
data = d;
}
void Call()
{
func(data);
}
};
class Callback
{
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
// Need to make this a class member;
CallbackFunction <T> *CallbackClass = func;
}
void Call()
{
CallbackClass->Call();
}
};
template <typename CT>
Callback *NewCallback(void (*func)(CT), CT *data)
{
Callback *cb;
CallbackFunction <CT> *cf;
cf->SetCallbackData(func, data);
cb->SetCallback <CT> (cf);
return cb;
};
void Call(Callback *CallbackFunc)
{
CallbackFunc->Call();
}
void foo(std::string str)
{
std::cout << str << "\n";
}
int main()
{
std::string *str;
str->append("Hello, World!");
Call( NewCallback(foo, str) );
return 0;
}
More details:
I know it's buggy, and it doesn't compile, I'll sort out those bugs when I find a solution to my problem. Which is:
I need to find a way to declare a template variable inside a member function of the class "Callback". I need to do this because the class "Callback" cannot be a template, it needs to remain a simple class. So because the class "Callback" is not a template, I need to make one of it's member functions a template instead. So that member function can declare a variable of the type defined (with the template) when the function is called, and this variable needs to be accessible to the entire class.
So in a nice list:
class "Callback" cannot be a template,
variable CallbackClass must be accessible to the entire class,
but remain inside of the class.
#include <iostream>
#include <string>
#include <memory>
template <typename MT>
class CallbackFunction
{
typedef void (*func_ptr)(MT);
func_ptr f_ptr;
typedef std::shared_ptr<MT> data_ptr;
data_ptr data_p;
public:
void SetCallbackData (func_ptr f_ptr_, MT *d)
{
f_ptr = f_ptr_;
data_p.reset(d);
}
void Call()
{
if ( f_ptr ) f_ptr(data);
}
};
template<class T>
class Callback
{
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
f_ptr.reset(func);
}
void Call()
{
if ( f_ptr ) f_ptr->Call();
}
typedef std::shared_ptr<CallbackFunction<T>> func_ptr;
static func_ptr f_ptr;
};
I would implement this using polymorphism. Your programming skills seem good so I will just sketch the direction to solution, feel free to ask for more help if needed.
// your callbackobjects inherit from this class, the sole purpose of this
// class is to provide the Call interface. The derived classes implement
// their custom version of Call().
class CallBackObject{
public:
virtual void Call(){};
};
class Callback
{
CallBackObject *callBackObject;
public:
void SetCallback(CallBackObject *o)
{
callBackObject = o;
}
void Call()
{
callBackObject -> Call();
}
};
Create an abstract interface Callback class and have your CallbackFunction<T> inherit from this. Have your Callback class hold a pointer to this abstract interface. Finally, have your Callback::SetCallback assign func to this pointer.
Here's some code to illustrate the idea:
class ICallback
{
public:
virtual ~ICallback() {}
virtual void Call() = 0;
};
template <typename MT>
class CallbackFunction : public ICallback
{
typedef void (*callback)(MT);
callback myfunc;
MT *data;
public:
CallbackFunction (callback f, MT *d) :
myfunc (f),
data (d)
{}
void Call()
{
if(myfunc && data)
{
myfunc(*data);
}
else throw std::logic_error("Callback function or data is null!");
}
};
Then have Callback hold a ICallback*:
class Callback
{
ICallback *mycallback;
public:
template <typename T>
void SetCallback(CallbackFunction <T> *func)
{
// Need to make this a class member;
// CallbackFunction <T> *CallbackClass = func;
mycallback = func;
}
void Call()
{
mycallback->Call();
}
};
The idea is to make all instantiated templates of CallbackFunction <T> a kind-of ICallback. Now the class using ICallback can take any class CallbackFunction <T> without needing to know what T is.
I have this code:
#ifndef FUNCSTARTER_H
#define FUNCSTARTER_H
#endif // FUNCSTARTER_H
#include <QObject>
class FunctionStarter : public QObject
{
Q_OBJECT
public:
FunctionStarter() {}
virtual ~FunctionStarter() {}
public slots:
void FuncStart(start) {
Start the function
}
};
In the FuncStart function, you would put your function in as a parameter and then it would execute the parameter (aka the function). How would I do this?
either you pass a function pointer, or you define a functor class. A functor class is a class that overloads operator(). This way, the class instance becomes callable as a function.
#include <iostream>
using namespace std;
class Functor {
public:
void operator()(void) {
cout << "functor called" << endl;
}
};
class Executor {
public:
void execute(Functor functor) {
functor();
};
};
int main() {
Functor f;
Executor e;
e.execute(f);
}
You'd pass the function pointer as parameter. This is called a callback.
typedef void(*FunPtr)(); //provide a friendly name for the type
class FunctionStarter : public QObject
{
public:
void FuncStart(FunPtr) { //takes a function pointer as parameter
FunPtr(); //invoke the function
}
};
void foo();
int main()
{
FunctionStarter fs;
fs.FuncStart(&foo); //pass the pointer to the function as parameter
//in C++, the & is optional, put here for clarity
}