Understanding error with taking address of non-static member to form pointer to member function?

江枫思渺然 提交于 2019-12-23 05:31:12

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!