2011-09-28 67 views
100

對於一個類,我想在一個map存儲std::function對象中存儲一些指向同一類的成員函數的函數指針。但是,我不就在與此代碼開頭:在一個類中使用具有成員函數的泛型std :: function對象

class Foo { 
    public: 
     void doSomething() {} 
     void bindFunction() { 
      // ERROR 
      std::function<void(void)> f = &Foo::doSomething; 
     } 
}; 

我收到xxcallobj有一些奇怪的模板實例化的錯誤結合error C2064: term does not evaluate to a function taking 0 arguments。目前我正在使用Visual Studio 2010/2011在Windows 8上工作,在使用VS10的Win 7上工作也會失敗。該錯誤必須基於我不遵循的一些奇怪的C++規則。

編輯:我做不是使用助推。這是集成在MS編譯器中的C++ 11。

+0

正確的答案是使用MSVC2013不支持的'std :: invoke'。這個問題有點過時了。 – Mikhail

回答

180

非靜態成員函數必須被一個對象調用。也就是說,它總是隱含地傳遞「this」指針作爲它的參數。

因爲你std::function簽名指定你的函數不帶任何參數(<void(void)>),您必須綁定第一個(也是唯一的)參數。

std::function<void(void)> f = std::bind(&Foo::doSomething, this); 

如果你想綁定參數的函數,你需要指定佔位符:

using namespace std::placeholders; 
std::function<void(int,int)> f = std::bind(&Foo::doSomethingArgs, this, _1, _2); 

或者,如果你的編譯器支持C++ 11 lambda表達式:

std::function<void(int,int)> f = [=](int a, int b) { 
    this->doSomethingArgs(a, b); 
} 

(我目前沒有支持C++ 11的編譯器現在,所以我不能檢查這個。)

+1

由於我不依賴於提升,我會使用lambda表達式;)然而,謝謝! –

+3

@AlexB:Boost.Bind不使用ADL作爲佔位符,它將它們置於匿名名稱空間中。 – ildjarn

+11

我建議避免全局捕獲[=]並使用[this]使捕獲的內容更清晰(Scott Meyers - 有效的現代C++第6章第31項 - 避免默認捕獲模式) –

53

要麼你需要

std::function<void(Foo*)> f = &Foo::doSomething; 

,這樣就可以把它在任何情況下,或者你需要綁定一個特定的實例,例如this

std::function<void(void)> f = std::bind(&Foo::doSomething, this); 
3

如果你需要存儲一個成員函數沒有類的實例,你可以做這樣的事情:

class MyClass 
{ 
public: 
    void MemberFunc(int value) 
    { 
     //do something 
    } 
}; 

// Store member function binding 
auto callable = std::mem_fn(&MyClass::MemberFunc); 

// Call with late supplied 'this' 
MyClass myInst; 
callable(&myInst, 123); 

會是什麼樣的存儲類型的樣子,而不汽車? 事情是這樣的:

std::_Mem_fn_wrap<void,void (__cdecl TestA::*)(int),TestA,int> callable 

您也可以通過這個功能,存儲空間爲標準功能結合

std::function<void(int)> binding = std::bind(callable, &testA, std::placeholders::_1); 
binding(123); // Call 

過去和未來的筆記:一箇舊的接口的std :: mem_func存在,但由於已被棄用。存在一個提案,發佈C++ 17,製作pointer to member functions callable。這將是最受歡迎的。

+0

@Danh'std :: mem_fn' was **不**刪除;一堆不必要的重載是。另一方面'std :: mem_fun'已被C++ 11棄用,並將被C++ 17刪除。 –

+0

@Danh這正是我所說的;)第一個「基本」重載仍然存在:'template 未指定的mem_fn(RT :: *);',並且它不會去遠。 –

+0

@Danh仔細閱讀[DR](https://cplusplus.github.io/LWG/lwg-defects.html#2048)。 DR中13個過載中的12個被刪除。最後一個*不是*(不會是;在C++ 11或C++ 14中都不會)。 –

相關問題