2012-09-27 33 views
3

我製作了包含函數的向量,但他們沒有參數列表。另外,他們不在課堂內。我有一個名爲Dialog的類,我需要存儲具有特定簽名的函數指針。這是我對這些功能的typedef:帶參數的函數向量

typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM); 

但是,因爲它包含這些MsgHandler的將是我Dialog類,這將是我的CMainWnd類被繼承,當我嘗試的push_back功能的載體,該功能的簽名與MsgHandler不同。這是我的代碼,試圖的push_back載體中的功能時,4種變異和由此得到的誤差爲它們中的每:

typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM); 

class Dialog 
{ 
protected: 
    Dialog(void); // Must be inherited 
    vector<MsgHandler> Handlers; 
} 

class CMainWnd : public Dialog 
{ 
public: 
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) { 
     return TRUE; 
    } 

    CMainWnd(void) { 
     // Attempt 1: Handlers.push_back(MyHandler); 
     // Attempt 2: Handlers.push_back(&MyHandler); 
     // Attempt 3: Handlers.push_back(CMainWnd::MyHandler); 
     // Attempt 4: Handlers.push_back(&CMainWnd::MyHandler); 
    } 
}; 

嘗試1產生以下錯誤:

error C3867: 'CMainWnd::MyHandler': function call missing argument list; use '&CMainWnd::MyHandler' to create a pointer to member 

嘗試2產率:

error C2276: '&' : illegal operation on bound member function expression 

嘗試3個產率:

error C3867: 'CMainWnd::MyHandler': function call missing argument list; use '&CMainWnd::MyHandler' to create a pointer to member 

嘗試4名,得到:

error C2664: 'std::vector<_Ty>::push_back' : cannot convert parameter 1 from 'INT_PTR (__thiscall CMainWnd::*)(WPARAM,LPARAM)' to 'const MsgHandler &' 

我想嘗試4是最接近是正確的,但如前所述,因爲函數是一個成員,它改變了簽名。 如何可以存儲在矢量函數指針是在繼承Dialog類定義:

  • 具有INT_PTR
  • 返回類型具有兩個參數,第一個是一個WPARAM,並且第二個是一個LPARAM
  • 是派生類,其constuctor是一個將它們添加到

聽說用boost::function FO的載體中的一員做這樣的事情,但我已經查閱了它的文檔,我不知道如何使用它,這一切似乎讓我感到困惑。我非常想將這些函數添加到向量中,就好像它們是變量一樣,而不是通過綁定操作讓我的代碼陷入困境,而不是(可能只是因爲我對boost函數無知)。

有人能幫我弄清楚我在這裏做錯了什麼,或者告訴我如何使用boost::function來做到這一點?對於boost::function的方法,我試過聲明矢量爲vector<boost::function<INT_PTR(WPARAM,LPARAM)>>,並嘗試添加MyHandler,但沒有奏效。如果我不需要,我寧願不使用提升,但如果有人建議這樣做的推動方式,請說明我該如何做到這一點?

非常感謝你們。

回答

4

這是如果你有機會到C++ 11 lambda表達式在那裏真正發光。我要改變你的代碼一點點,只是因爲它是稍微容易得到它爲我工作,但你應該能夠解決它爲您的需求很容易:

#include <vector> 
#include <functional> 
#include <iostream> 

class Dialog 
{ 
protected: 
    Dialog() { } // Must be inherited 
    std::vector<std::function<bool (int, int)>> Handlers; 
}; 

class CMainWnd : public Dialog 
{ 
public: 
    bool MyHandler(int wp, int lp) 
    { 
     std::cout << "(" << wp << ", " << lp << ")\n"; 
     return true; 
    } 

    CMainWnd() 
    { 
     Handlers.push_back([this](int wp, int lp) -> bool { return this->MyHandler(wp, lp); }); 
     std::cout << Handlers[0](1,1) << "\n"; 
    } 
}; 

int main() 
{ 
    CMainWnd c; 
    return 0; 
} 

編輯:當使用C++ 03和升壓代替:

#include <boost/function.hpp> 
#include <boost/bind.hpp> 

class Dialog 
{ 
protected: 
    Dialog() { } // Must be inherited 
    std::vector<boost::function<bool (int, int)> > Handlers; 
}; 

class CMainWnd : public Dialog 
{ 
public: 
    bool MyHandler(int wp, int lp) 
    { 
     std::cout << "(" << wp << ", " << lp << ")\n"; 
     return true; 
    } 

    CMainWnd() 
    { 
     Handlers.push_back(boost::bind(&CMainWnd::MyHandler, this, _1, _2)); 
     std::cout << Handlers[0](1,1) << "\n"; 
    } 
}; 
+3

沒有需要在這裏的lambda:'處理程序。push_back(std :: bind(CMainWnd :: MyHandler,this));'應該這樣做。 –

+0

@MichaelAnderson:我會反擊,並說不需要'std :: bind',我們有lambda。這只是我個人的偏好。 –

+0

@MichaelAnderson的確,我實際上已經忘記了你可以用'std :: bind'綁定'this'。 – Yuushi

0

這是一個webpage描述你的問題。

類成員函數只是不正常的函數。 如果聲明一個正常的函數對你來說沒問題(在這個例子中似乎沒問題),就這樣做。

Are a member of the derived class whose constuctor is the one adding them to the vector

如果您真的必須使用c函數指針來創建類的函數成員, 我不知道你是否可以在類聲明範圍內聲明一個非成員函數成員函數,如果可以的話,這樣做。

好運

+0

我用正常功能前,在矢量加,但現在我必須使用成員函數循環添加成員向量。並感謝好運,因爲它似乎我需要它。 –

3

想一想:當您創建函數指針的向量,什麼是向量的每個元素的大小?這是正確的,一個函數指針的大小。現在,你怎麼能期望它保存指向函數的指針以及指向該函數應該被調用的對象的指針?

C++語言功能是圍繞「支付你所用的」原則而設計的。所以函數指針儘可能的輕。現在,你想要的就是代表。代表不是C++中的語言特性,因此,不管你喜歡它,你需要使用boost :: function(或者自己寫)。有更快委託的解決方案比的boost ::順便說一下功能,您可以檢查:this code projectthis one

以下是如何與提升做::功能:

#include <vector> 
using namespace std; 
#include <boost/function.hpp> 
#include <boost/bind.hpp> 

typedef int INT_PTR; 
typedef int WPARAM; 
typedef int LPARAM; 

//typedef INT_PTR (*MsgHandler)(WPARAM,LPARAM); 
typedef boost::function<INT_PTR(WPARAM,LPARAM)> MsgHandler; 

class Dialog 
{ 
protected: 
    Dialog(void){} // Must be inherited 
    vector<MsgHandler> Handlers; 
}; 

class CMainWnd : public Dialog 
{ 
public: 
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) { 
     return true; 
    } 

    CMainWnd(void) { 
     // Attempt 1: Handlers.push_back(MyHandler); 
     // Attempt 2: Handlers.push_back(&MyHandler); 
     // Attempt 3: Handlers.push_back(CMainWnd::MyHandler); 
     // Attempt 4: Handlers.push_back(&CMainWnd::MyHandler); 
    Handlers.push_back(boost::bind(&CMainWnd::MyHandler, this, _1,_2)); 
    } 
}; 

int main() { 
    CMainWnd w; 

} 

這裏是一個與難以置信的快代表(用正確設置課程包括路徑)

#include <vector> 
using namespace std; 
#define SRUTIL_DELEGATE_PREFERRED_SYNTAX 
#include <srutil/delegate/delegate.hpp> 

typedef int INT_PTR; 
typedef int WPARAM; 
typedef int LPARAM; 

typedef srutil::delegate<INT_PTR(WPARAM,LPARAM)> MsgHandler; 

class Dialog 
{ 
protected: 
    Dialog(void){} // Must be inherited 
    vector<MsgHandler> Handlers; 
}; 

class CMainWnd : public Dialog 
{ 
public: 
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) { 
     return true; 
    } 

    CMainWnd(void) { 
    Handlers.push_back(MsgHandler::from_method<CMainWnd, 
       &CMainWnd::MyHandler>(this)); 
    } 
}; 

int main() { 
    CMainWnd w; 
} 
+0

我意識到我可能不得不使用boost :: function,但正如我所說我不知道​​如何使用它。試圖將這些添加到矢量中對我來說更加複雜。我希望看起來好像我並沒有試圖讓你爲我做'功課',但是看着這兩個頁面只會讓我覺得自己陷入了一種遠遠超出我的知識的境地。 –

+0

而在不可能的快速委託頁面中,它使用一個實例化的對象。我試圖在我的類構造函數中將這些委託添加到一個向量中,而不是使用該類的實例化。 –

+1

@BrandonMiller我已經添加了boost :: function的方法 – enobayram

1

在C++中,您通常會使用std::function或其提升等效值。然而,這是一種C風格的解決方案,可能適用於某些情況 - 這是存儲和傳遞額外的用戶數據到函數。

typedef INT_PTR (*MsgHandlerFn)(WPARAM,LPARAM, void*); 
struct MsgHandler 
{ 
    MsgHandler( 
    MsgHandlerFn in_fn, 
    void * in_user_data) 
    : fn(in_fn), user_data(in_user_data) 
    {} 
    //TODO: Add copy constructor, assignment operator, default constructor 
    MshHandlerFn fn; 
    void * user_data; 
}; 

class Dialog 
{ 
protected: 
    Dialog(void); // Must be inherited 
    vector<MsgHandler> Handlers; 
}; 

class CMainWnd : public Dialog 
{ 
    public: 
    INT_PTR MyHandler(WPARAM wp, LPARAM lp) { 
     return TRUE; 
    } 
    protected: 
    static INT_PTR MyHandlerStatic(WPARAM wp, LPARAM lp, void * user_data) 
    { 
     return static_cast<CMainWnd*>(user_data)->MyHandler(wp,lp); 
    } 
    public: 
    CMainWnd(void) { 
     Handlers.push_back(MsgHandler(&CMainWnd::MyHandlerStatic, this)); 
    } 
}; 

現在您的對話框調用處理程序將需要看起來更像這個

for(unsigned int i=0; i<Handlers.size(); ++i) 
    Handlers[i].fn(wp,lp, Handlers[i].user_data); 
+0

那麼,那種方式是非常醜陋的,實際上需要更多的代碼,而不需要使用函數向量。但我會給你+1純C的方式做到這一點:) –