2012-10-02 185 views
0

我正在考慮創建一個使用Win32 API和C++標準庫的Window類庫
我想添加處理窗口的信號/插槽功能消息。將boost :: bind對象轉換爲函數指針 - 實現消息映射

using namespace std; 
using namespace boost::signals2; 
typedef signal<void (Window*, EventArgs*)> WndEvent; 

class EventArgs { public: HWND hWnd; WPARAM wParam; LPARAM lParam; }; 

class Window { 
    protected: unordered_map<UINT, WndMsg*> msgMap; 
    public: void addMsgHandler(UINT msg, void (*handler)(Window*, EventArgs*)) { 
     auto iter=msgMap.find(msg); 
     if(iter==msgMap.end()) { 
      WndEvent* newEvent = new WndEvent(); 
      newEvent->connect(handler); 
      msgMap.insert(make_pair(msg, newEvent)); 
     } 
     else iter->second->connect(handler); 
    } 

    private: LRESULT wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam) { 
     for(auto iter=msgMap.begin(); iter!=msgMap.end(); iter++) 
      iter->second->(); 
    } 
}; 

在使用該庫:

class Form : public Window { 
    void initialize() {// add here pair of 'message' and 'corresponding handler' 
     addMsgHandler(WM_LBUTTONUP, boost::bind(&Form::onLButtonUp, this, _1, _2)); 
     ... 
    } 
    void onLButtonUp(Window* sender, EventArgs* e) { // event handler 
     wchar_t buf[1000]; 
     wsprintf(buf, L"(%d, %d) clicked", GET_X_LPARAM(e->lParam), GET_Y_LPARAM(e->lParam)); 
     MessageBox(0, buf, L"", MB_OK); 
    } 
} 

這裏的問題是onLButtonUp的簽名不匹配,因爲它是一個類的成員函數。
所以,我想使用boost ::綁定,我得到了編譯錯誤是這樣的:

Window::addMsgHandler': cannot convert parameter 2 'boost::_bi::bind_t<R,F,L>' to 'void (__cdecl *)(Window *,EventArgs *)' 

,這意味着我必須要改變(?從簡單的函數指針,以提高函數對象)addMsgHandler的簽名(),但

我無法確定要傳遞的數據類型(具有很長的模板參數)。

編譯錯誤消息稱

R=void,    
F=boost::_mfi::mf2<void,Form,Window *,EventArgs *>,1>       
L=boost::_bi::list3<boost::_bi::value<Form*>,boost::arg<1>,boost::arg<2>>     

此外,由於許多其他類從Window類派生的,我不知道該模板類型時,我定義類窗口

有沒有適當的方式來傳遞boost.bind對象作爲函數參數?

+0

我不想存儲函數指針,但信號。 boost.function可以存儲信號嗎? –

+0

恐怕我不明白你的意思,但是......然後,我應該將'msgMap'的類型從map更改爲multimap,將函數添加到該multimap中,並且每次給出消息(WM_'s)時重新連接()所有的處理程序到相應的boost :: signal,並觸發信號?這不奇怪嗎?我認爲應該爲每個處理程序調用一次connect()。 –

+0

我首先想到的情況是這樣的:在地圖中存儲connect()'ed信號,而不是函數本身 –

回答

0

將其定義是這樣的:

void addMsgHandler(UINT msg, const function<void(Window* , EventArgs*)>& slot); 

甚至是這樣的:

void addMsgHandler(UINT msg, const WndEvent::slot_type &slot); 

現在,調用這個函數時,slot參數應該是一個 「可贖回」 接受的類型Window * 2個參數和EventArgs *,並且您可以使用mem_fn,boost::bind,std::bind或僅傳遞適當的原始函數ptr來創建這樣的插槽。

+0

謝謝。實現了第一個和應用程序的正常工作,即使是派生類Form。現在我可以像這樣使用addMsgHandler:addMsgHandler(WM_LBUTTONUP,bind(&Form :: onLButtonUp,this,_1,_2)); –

+0

@傑弗裏Goines ok,太好了。但在我看來,第二種形式更好,因爲它使你的意圖更清楚。如果你改變了WndEvent簽名,'addMsgHandler'不需要改變。 –