2013-10-15 82 views
2

我想創建一個菜單句柄來代替這樣的結構:創建具有升壓綁定一個菜單句柄/功能

void MyClass::handleMenu(MenuID id) { 
    switch (id) { 
    case option1: doFunction1(); break; 
    case option2: doFunction2(true); break; 
    case option3: memberVariable->doOtherFunction(); break; 
    } 
} 

隨着菜單項的數量的增加,有switch語句,所以我想切換到一個機制,在該機制中菜單是通過響應菜單通知調用的一些功能對象來設置的。某些函數可能會採用其他參數(在安裝時已知),有些函數可能會調用成員函數。

我有一種感覺,它應該是這個樣子:

void MyClass::setupMenu() { 
    std::map<MenuID, boost::function<void()>> idMap; 
    idMap[option1] = boost::bind(&MyClass::doFunction1, _1, this); 
    idMap[option2] = boost::bind(&MyClass::doFunction2, _1, this, true); 
    idMap[option3] = boost::bind(&MemberClass::doOtherFunction, _1, memberVariable); 
} 

void MyClass::handleMenu(MenuID id) { 
    auto f=idMap[id]; 
    f(); // invoke callback  
} 

但是,我不能得到boost::function類型和bind調用的正確組合。也許由於某些函數可能會返回一個值,這很複雜,但是在菜單處理代碼中,我們並不關心這個,我們可以將其視爲無效。編譯器錯誤往往出現在將bind的結果插入到映射中的調用中。我錯過了一個更簡單的方法來做到這一點?

編輯:

@坦率的方式工作,但我發現了一個問題,我沒有預料到的:如果你想通過代碼介入調試器來查找得到由該菜單項,然後執行該功能這是相當困難的,因爲在進入實際的函數調用之前,您必須進入和退出boost::bind代碼的幾個層。調試人員沒有完全跟上boost和tr1的流血邊緣,這真令人遺憾。

+0

刪除'_1'。他們將代表一個函數(至少)1個參數。您的定義idMap不使用任何參數。 – dornhege

+0

其實,可以用'mem_fun'(或'mem_fn')來簡化嗎? –

回答

2

C++成員函數的第一個參數是this-pointer。

boost :: bind使函數對象形成函數指針及其傳遞的參數。 _1,_2 ...是佔位符(lambda)。當函數對象被調用時它們將被傳遞。

class MyClass{ 
    /// Callback signature for calling the function for a specific command. 
    typedef boost::function<void()> TMenuCmdCallback; 
    int doFunction1(bool); 
    void doFunction2(); 
    double doFunction3(int); 
    void setupMenu(){ 
    TMenuCmdCallback callback; 
    m_Callbacks[ 1] = boost::bind(&MyClass::doFunction1, this, true); // allways pass true 
    m_Callbacks[10] = boost::bind(&MyClass::doFunction1, this, false); // allways pass false 
    m_Callbacks[ 2] = boost::bind(&MyClass::doFunction2, this); 
    m_Callbacks[ 3] = boost::bind(&MyClass::doFunction3, this, this->m_Int); 
    } 
    void callFunction(int index) 
    { 
    m_Callbacks[index](); 
    } 
    std::map<int, TMenuCmdCallback> m_Callbacks; 
    int m_Int; 
}; 

在我的例子中,我不檢查索引是否超出範圍。 在這個例子中,我不需要lambdas,因爲在運行時(在callFunction中)我沒有參數可以傳遞。

我不確定函數3的回調是否真的起作用(但至少編譯過)。

+0

當然只有'doFunction2'匹配這裏的回調簽名? –

+0

@ Moo-Juice:'boost :: bind'提供了所有要使用的參數,以便稍後可以在沒有參數的情況下調用回調。 – aschepler

+0

注意,當調用setupMenu()時,綁定到'this-> m_Int'將傳遞值'm_Int'。如果你想在回調的時候使用'm_Int'的值,可以嘗試綁定'boost :: ref(m_Int)'。 – aschepler