如何使用 bind 将成员函数作为函数指针传递?

How do I use bind to pass a member function as a function pointer?

我正在尝试将成员函数作为函数指针传递,这样我就不需要依赖单例或全局函数来处理 Qt 5 中的 Qt 消息。据我所知 std::function 是正确的类型,它有正确的签名,并且 bind 应该允许我插入隐式 this 指针,本质上是将成员函数作为 global/un-owned 函数传递。

void ProgramMessageHandler::setAsMessageHandlerForProgram() {
    std::function<void(QtMsgType, const QMessageLogContext &, const QString &)> funcPtr;

    funcPtr = std::bind(handleMessages, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);

    qInstallMessageHandler(funkPtr);
}

这无法编译。我可以成功创建 funcPtr 变量,但将其传递到 qInstallMessageHandler 函数会导致以下结果:

log\ProgramMessageManager.cpp:16: error: cannot convert 'std::function<void(QtMsgType, const QMessageLogContext&, const QString&)>' to 'QtMessageHandler {aka void (*)(QtMsgType, const QMessageLogContext&, const QString&)}' for argument '1' to 'void (* qInstallMessageHandler(QtMessageHandler))(QtMsgType, const QMessageLogContext&, const QString&)'
 oldHandler = qInstallMessageHandler(hackedPointerToHandleFunction);
                                                                  ^

我已阅读:

how to pass a member function as a function pointer?

How do you pass a member function pointer?

How to pass a member function as a parameter to a function that doesn't expect it?

Get function pointer from std::function when using std::bind

但是 none 帮助了我。

编辑:

所以有人说如果没有单例或全局函数这是不可能的...但是为什么呢?具有相同签名的成员函数和全局函数之间的唯一区别是它们具有相同的签名,有一个隐式的this指针作为第一个参数到成员函数。

知道了,为什么我不能使用 std::bind 来弥合这个差距,通过说'我知道被调用的函数在所有其他函数之前采用 this 参数,强制它在那里,是知道this的东西。这比单例要干净得多,而全局函数只是废话。

您正在尝试传递 class 实例,其中需要 函数指针 ,但不存在此类转换。

你可以这样做:

class ProgramMessageHandler
{
  static void  myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);
};

在main.cpp中(例如):

...
qInstallMessageHandler(ProgramMessageHander::myMessageHandler);
...

您可能仍然需要像在单例中那样处理一些问题 classes,但我认为有一个消息处理程序或至少一个调度程序以某种方式将不同的消息重定向到适当的处理程序是有意义的.希望这有帮助

std::bind 的结果是一个函数对象,正如错误消息所说,您不能将函数对象转换为函数指针。函数指针不能像 std::function 那样存储 this 指针,你不能只存储 "force it in there".

做一些接近你想要的事情的唯一方法是使用单例来存储 this 指针:

class ProgramMessageHandler {
private:
  static ProgramMessageHandler* currentHandler;
  void handleMessagesImpl(const std::string& message);
public:
  void setAsMessageHandlerForProgram(){
    currentHandler = this;
    qInstallMessageHandler(handleMessages);
  }
  static void handleMessages(const std::string& message) { 
    if (currentHandler) 
      currentHandler->handleMessagesImpl(message);
  }
};

ProgramMessageHandler* ProgramMessageHandler::currentHandler = nullptr;

int main() {
  ProgramMessageHandler handler;
  handler.setAsMessageHandlerForProgram();

  // trigger messages...
}

Live demo.