理解获取非静态成员地址以形成指向成员函数的指针的错误?

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

我有一个问题,我不确定如何解决。

我正在使用一个库,其 class 的实例是通过传递对一些函数的引用来构造的。

void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}

State state_a(&func_on_enter, &func, &func_on_exit);

我正在写一个 class,其中包含此 class 的一个实例,因此我尝试过这样的事情:

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

我收到错误 "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'"(显然其他两种方法也一样)。编译器很有帮助地提供了一个解决方案,我试过了。

但是编译器随后提醒我没有匹配函数来调用 'State::State(void (MyClass::*)(), void (MyClass::*)(), (MyClass::*)())' 并且它没有已知的从 'void (MyClass::*)()''void(*)()' 的转换。

我尝试阅读有关此错误的类似问题,但似乎找不到我既理解又能在这种情况下提供帮助的解决方案。

我考虑过尝试向 State 添加一个重载构造函数,但是考虑到我可以从任何其他 [=36] 调用它,在 class by class 情况下这样做似乎很荒谬=].

我也想了一会儿,我可以将函数设为静态(因为它们对于 MyClass 的所有实例都是相同的),但我很快记起它们将无法使用非静态成员变量MyClass 的。

有没有一种方法可以提供转换或以另一种方式为 State 构造函数提供指针?

在这方面我真的需要一些帮助,因为我对如何前进的想法很困惑。任何帮助或提示将不胜感激!

void func_on_enter() {...}
void func() {...}
void func_on_exit(){...}

State state_a(&func_on_enter, &func, &func_on_exit);

为此,State 的构造函数必须接受类型为 void(*)() 的函数指针。

_state_a(&MyClass::func_on_enter, &MyClass::func, &MyClass::func_on_exit)

为此,State 的构造函数必须接受 void (MyClass::*)() 类型的成员函数指针。成员函数指针不可转换为函数指针。

您可以更改 State 的构造函数以接受正确类型的指针。

指向非静态成员函数的指针无法转换为普通函数指针。 void (MyClass::*)() 需要一个 MyClass 对象来操作。原始指针不能保存任何类型的状态,因此 void(*)() 无法存储有关要操作哪个 MyClass 对象的信息。

幸运的是,标准库有一个 class 专为此目的设计的模板:std::functionstd::function 或多或少是原始函数指针的替代品,但它可以容纳与给定签名兼容的任何类型的可调用对象。这意味着它可以保持回调到 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

在这里,我没有将指针直接传递给您的成员函数,而是将它们包装在捕获要回调的对象的 this 指针的 lambda 中。现在 State 对象可以调用这些成员,并且他们知道要对 MyClass 的哪个实例进行操作。

不过要注意对象的生命周期。由于 state_a 保留指向其 MyClass 实例的指针,因此您需要确保 MyClass 的 copy/move 构造函数和赋值运算符做正确的事情。编译器提供的默认实现是不够的。