1
votes

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

2
&Update is not a void (*)(). This code can't work. What is your question? - melpomene
My Question is how to change Update to make is work - Kay Hennig
You'd have to make Update static to get that type. - melpomene
What are you trying to solve? Update is a non-static member, it has an implicit this argument. How do you expect to provide it at the call site? - StoryTeller - Unslander Monica

2 Answers

1
votes

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.

0
votes

The problem

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.

First solution : member function pointer

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);
}

Online demo

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.

Better solution: command pattern

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.