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

时间:2015-09-15 10:30:54

标签: qt c++11 stdbind

我试图将成员函数作为函数指针传递,这样我就不需要依赖单例或全局函数来处理Qt 5中的Qt消息了。据我所知,我可以告诉我的std :: function的类型正确,它具有正确的签名,bind应该允许我在隐式this指针中堵塞,基本上将成员函数作为全局/非拥有函数传递。

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

但没有人帮助过我。

修改

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

知道了,为什么我不能使用std::bind来弥补这个差距,通过说&#39;我知道被调用的函数在所有其他函数之前采用this参数,强制它在那里,知道this的事情。那将比单身人士更清洁,全球职能只是废话。

2 个答案:

答案 0 :(得分:2)

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

你可以这样做:

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

在main.cpp中(例如):

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

你仍然可能需要处理单例类中的一些问题,但我认为有一个消息处理程序或至少一个调度程序可以某种方式将不同的消息重定向到适当的处理程序。希望这有帮助

答案 1 :(得分:1)

std::bind的结果是一个函数对象,正如错误消息所示,您无法将函数对象转换为函数指针。函数指针不能存储像this那样的std::function指针,你只能强迫它在那里&#34;。

做一些接近你想要的事情的唯一方法是使用单例来存储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...
}

{{3}}