Reputation: 7
In SomeClass.h
class SomeClass{
public:
static std::vector<void (*)()> UpdateFuncs;
}
In OtherClass.h
class OtherClass{
private:
void Update();
public:
OtherClass();
}
In OtherClass.cpp
OtherClass::OtherClass(){
Time::UpdateFuncs.push_back(&(this->Update));
}
On Build I get '&':
illegal operation on bound member function expression
and if I do:
.push_back(&Update);
Then I get "no instance of overloaded function
std::vector<_Ty, _Alloc>::push_back [with _Ty=void (*)(), _Alloc=std::allocator]" matches the argument list"
Thank in advance
Upvotes: 1
Views: 492
Reputation: 73376
You try to assign to an ordinary function pointer of type void(*)()
a member function pointer of type void(OtherClass::*)()
.
Unfortunately these two types are incompatible: an ordinary function can be called with only its parameters, and a member function pointer can only be called for a specific object.
You have to change the definition of the vector to make it use a member function pointer.
class OtherClass; // forward deaclaration
class SomeClass {
public:
static std::vector<void (OtherClass::*)()> UpdateFuncs;
};
Then you can pushback the function as expected:
OtherClass::OtherClass() {
SomeClass::UpdateFuncs.push_back(&OtherClass::Update);
}
Unfortunately you can't mix it with member function pointers to other classes or ordinary function pointers. And you have to specify the object to use at the moment you invoke your function.
The command pattern allows you more flexibility than function pointers. Thanks to specialization of commands, you can mix commands that will invoke ordinary function pointers, member function pointers of different classes, or ad-hoc functions.
The commands could look like this:
class Command {
public:
virtual void execute() = 0;
virtual ~Command();
};
class CommandOtherClass : public Command {
OtherClass *target;
void (OtherClass::*f)();
public:
CommandOtherClass (void (OtherClass::*fct)(), OtherClass*t);
void execute() override;
};
The implementation is really straightforward:
CommandOtherClass::CommandOtherClass (void (OtherClass::*fct)(), OtherClass*t)
: f(fct),target(t)
{
}
void CommandOtherClass::execute() {
(target->*f)();
}
The SomeClass function could be changed as follows:
class SomeClass {
public:
static std::vector<unique_ptr<Command>> UpdateFuncs;
static void executeAll();
};
Note that you could develop it so to include a registration and unregistration functions, so that you can also remove from the vector commands involving objects that no longer exist.
Adding a new command to the vector would be done like this:
OtherClass::OtherClass() {
SomeClass::UpdateFuncs.push_back(make_unique<CommandOtherClass>(&OtherClass::Update, this));
}
Finally, here a complete online demo that invokes two commands automatically registered for some local objects, and even add a third ad hoc command unrelated to any other object.
Upvotes: 0
Reputation: 27528
OtherClass::Update
is not suitable for a void (*)()
function pointer, because it's a non-static member function; it's as if it had an "invisible" OtherClass*
parameter.
Use std::function
to achieve your goal:
#include <functional>
class Time
{
public:
static std::vector<std::function<void()>> UpdateFuncs;
};
In OtherClass.cpp, use a this
-capturing lamba as a function object:
OtherClass::OtherClass()
{
Time::UpdateFuncs.push_back([this] { Update(); });
}
Of course, if you make Update
static, then you can still work with void (*)()
if you want to, because the "invisible" parameter is removed, but std::function
is just the safe and modern way to do it.
Upvotes: 1