问题
I have an issue that I'm not sure how to get around.
I am using a library whose instances of the class are constructed by being passed references to a few functions.
void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}
State state_a(&func_on_enter, &func, &func_on_exit);
I am writing a class that contains an instance of this class, and as such have attempted something like this:
class MyClass{
private:
void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}
State _state_a;
public:
MyClass() : _state_a(&func_on_enter, &func, &func_on_exit) {}
};
I get the error "ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&MyClass::_func_on_enter'" (and the same for the other two methods obviously). The compiler helpfully provides a solution, which I tried.
However the compiler then reminds me that there is no matching function for a call to 'State::State(void (MyClass::*)(), void (MyClass::*)(), (MyClass::*)())'
and that it has no known conversion from 'void (MyClass::*)()'
to 'void(*)()'
.
I tried reading up on similar questions about this error but can't seem to find a solution that I both understand and can help in this situation.
I considered trying to add an overload constructor to State, but this seems absurd to do on a class by class case, considering that I could be calling it from any other class.
I also thought for a while that I could just make the functions static (as they're the same for all instances of MyClass), but I quickly remembered that they would then be unable to use non-static member variables of MyClass.
Is there perhaps a way that I can provide a conversion or provide the pointers for the State constructor in another way?
I could really do with some help on this, as I'm quite stuck for ideas on how to move forward. Any help or hints would be greatly appreciated!
回答1:
Pointers to non-static member functions cannot be converted to plain function pointers. A void (MyClass::*)()
requires a MyClass
object to operate on. Raw pointers can't hold any sort of state though, so there's no way for a void(*)()
to store the information about which MyClass
object to operate on.
Luckily, the standard library has a class template designed for just this purpose: std::function. std::function
is a more-or-less drop-in replacement for raw function pointers, but it can hold any type of callable object that's compatible with a given signature. That means it can hold the state required to call back to a specific instance of a class:
class State {
private:
std::function<void()> on_enter;
std::function<void()> func;
std::function<void()> on_exit;
public:
State(std::function<void()> on_enter, std::function<void()> func, std::function<void()> on_exit)
: on_enter{std::move(on_enter)},
func{std::move(func)},
on_exit{std::move(on_exit)}
{}
void do_something() {
on_enter();
// stuff
func();
// more stuff
on_exit();
}
};
class MyClass {
private:
void func_on_enter() {}
void func() {}
void func_on_exit(){}
State state_a;
public:
MyClass()
: state_a([this]() { func_on_enter(); },
[this]() { func(); },
[this]() { func_on_exit(); })
{}
};
Live Demo
Here, instead of passing pointers to your member functions directly, I've wrapped them in lambdas that capture the this
pointer of the object to be called back. Now the State
object is able to call those members, and they know which instance of MyClass
to operate on.
Be careful about object lifetime though. Since state_a
holds pointers back to its MyClass
instance, you'll need to ensure MyClass
's copy/move constructor and assignment operators do the right thing. The default implementations provided by the compiler aren't sufficient.
回答2:
void func_on_enter() {...} void func() {...} void func_on_exit(){...} State state_a(&func_on_enter, &func, &func_on_exit);
For this to work, the constructor of State
must be accepting of function pointers of type void(*)()
.
_state_a(&MyClass::func_on_enter, &MyClass::func, &MyClass::func_on_exit)
For this to work, the constructor of State
must be accepting of member function pointers of type void (MyClass::*)()
. Member function pointers are not convertible to function pointers.
You could change the constructor of State
to accept pointers of correct type.
来源:https://stackoverflow.com/questions/55513790/understanding-error-with-taking-address-of-non-static-member-to-form-pointer-to