2015-09-15 69 views
4

我試圖通過一個函數指針的成員函數,以便我不需要依靠單例或全局函數來處理Qt 5中的Qt消息。據我可以告訴我的std ::函數是正確的類型,它有正確的簽名,綁定應該允許我在隱式指針中阻塞,實際上是將全局/非全部函數的成員函數傳遞出去。如何使用bind將成員函數作爲函數指針傳遞?

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

但沒有人幫助過我。

編輯:

所以有人說,這是不可能沒有一個單身或全局funtion ......但是爲什麼呢?成員函數和具有相同簽名的全局函數之間唯一的區別在於它們不具有相同的簽名,並且存在隱含的指針作爲成員函數的第一個參數。

知道了,爲什麼我不能用std::bind彌合這一差距,說:「我知道,被調用的函數取this參數中的所有其他人的面前,迫使它在那裏,是知道this的東西。這比單身人士要乾淨得多,一個全球性的功能就是廢話。

+0

函數指針(與函數對象不同)可以沒有自己的狀態,所以無處可在「this」指針中「卡住」。 –

+0

@ChrisDrew但不是我的'std :: function'記錄它?我一直認爲'std :: bind'能夠通過跟蹤* extra *信息將不相同的東西綁定在一起,例如一個'this'指針... – Troyseph

+0

是的,一個'std :: function'可以跟蹤它。但'qInstallMessageHandler'不需要'std :: function'它需要一個函數指針。 –

回答

2

你試圖傳遞一個類實例其中函數指針預期,而沒有這樣的轉換存在。

你可以做這樣的事情:

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

在main.cpp中(例如):

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

您可能仍然不得不面對一些問題,如單班,但我認爲有意義的是,有一個消息處理程序或至少有一個調度程序會以某種方式將不同的消息重定向到適當的處理程序。希望這有助於

+0

我希望通過使用'std :: bind',我可以將我的實例函數指針暴露爲函數指針,然後在調用後的'this'參數中使用shoehorn。畢竟'std :: function '具有正確的函數簽名(即,根據我所知,不是實例簽名)。 – Troyseph

+0

@Troyseph'std :: bind'不返回函數指針,它返回一個函數對象。 –

+0

@ChrisDrew我無法獲得函數指針?是我的問題,我的'std :: function'不能是暫時的? – Troyseph

1

std::bind的結果是一個函數對象,並且如錯誤消息所述,不能將函數對象轉換爲函數指針。函數指針不能存儲this指針,如std::function可以,你不能只是「強迫它在那裏」。

做一些接近你想要的東西,唯一的方法是使用一個單獨存儲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

+0

幾乎完全是我解決的解決方案,爲什麼Qt在2015年的C++庫中使用C風格的語法擊敗了我......非常討厭! – Troyseph

+0

我想我真正希望得到的是'函數'對象擁有一個函數指針,我可以像平常一樣傳遞,它通過'bind' shenanigans綁定到我的成員函數......但事實並非如此。 – Troyseph

+1

爲了您的問題,他們爲什麼要使用這種語法,我假設只是因爲它爲他們節省了重寫大量源代碼的工作...... qInstallMessageHandler是qt 4.8中引入的舊函數qInstallMsgHandler的替代品,該版本於2011年12月發佈,僅在C++ 11獲得批准後的幾個月內(2011年8月)發佈。 – Anorflame

相關問題