2013-06-16 23 views
6

Mogę łatwo powiązać funkcje składowe z std::function, zawijając je wyrażeniem lambda z klauzulą ​​przechwytywania.Jak bezpośrednio powiązać funkcję składową do funkcji std :: w Visual Studio 11?

class Class 
{ 
    Class() 
    { 
     Register([=](int n){ Function(n); }); 
    } 

    void Register(std::function<void(int)> Callback) 
    { 

    } 

    void Function(int Number) 
    { 

    } 
}; 

Ale chcę je powiązać bezpośrednio, coś jak poniżej.

// ... 
Register(&Class::Function); 
// ... 

Myślę, że zgodnie ze standardem C++ 11 powinno to być obsługiwane. Jednak w Visual Studio 11 dostaję te błędy kompilatora.

error C2440: 'nowej linii': nie można przekonwertować z 'int' do 'klasa *'

error C2647: '*': nie można dereference o „void (__thiscall Class :: *) (int)”na 'int'

Odpowiedz

17

myślę według standardu C++ 11, powinno być wspierane

Nie bardzo, ponieważ nie-statyczna funkcja Użytkownik ma implic to pierwszy parametr typu (cv-kwalifikowany) YourType*, więc w tym przypadku nie pasuje on do void(int). Stąd potrzeba std::bind:

Register(std::bind(&Class::Function, PointerToSomeInstanceOfClass, _1)); 

Na przykład

Class c; 
using namespace std::placeholders; // for _1, _2 etc. 
c.Register(std::bind(&Class::Function, &c, _1)); 

Edycja wspomniałeś, że to ma być wywoływana z tego samego Class instancji. W takim przypadku można skorzystać z prostej funkcji non-użytkownik:

void (int n) foo 
{ 
    theClassInstance.Function(n); 
} 

następnie

Class c; 
c.Register(foo); 
+0

Works, ale może zostać uproszczona składnia pod przymusem, że wszystkie odniesienia klasy są takie same? – danijar

+0

@danijar co masz na myśli, gdy wszystkie odniesienia do klas są takie same? Musisz przekazać wskaźnik do instancji 'Class'. Który z nich przekazujesz zależy od ciebie. – juanchopanza

+0

Dobrze. I ta instancja zawsze będzie taka sama. Teraz chciałbym skrócić "bind (& Class :: Function, this, _1)" mając na uwadze te informacje. Więc treściowo "bind" jest przestarzały. Czy istnieje sposób na pozbycie się go lub wykonanie wiązania w funkcji po przejściu? – danijar

4

Można użyć std::bind:

using namespace std::placeholders; // For _1 in the bind call 

// ... 

Register(std::bind(&Class::Function, this, _1)); 
+0

Powiedz, chcę ustawić ten wskaźnik funkcji jako domyślny argument dla funkcji. czy to możliwe? Nie mogę wtedy używać wywołań typu "bind", prawda? Nie mam tego "wskaźnika" do znalezienia na liście parametrów. – danijar

+1

@danijar Nie jest to możliwe, ale można je obejść poprzez przeciążenie wariantu 'Register' bez żadnych argumentów wiążących się z domyślną funkcją. –

+0

Niezły pomysł, dzięki. – danijar

0

Z std::function i std::bind można traktować inny funkcja członka klasy jest taka sama.

#include <iostream> 
#include <functional> 
#include <vector> 
using namespace std; 
using namespace std::placeholders; 

class Foo 
{ 
public: 
    void foo(const string &msg) 
    { 
     cout << msg << '\n'; 
    } 
}; 

class Bar 
{ 
public: 
    void bar(const string &msg, const string &suffix) 
    { 
     cout << msg << suffix << '\n'; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    Foo foo; 
    Bar bar; 

    vector<function<void (const string &msg)>> collection; 
    collection.push_back(bind(&Foo::foo, &foo, _1)); 
    collection.push_back(bind(&Bar::bar, &bar, _1, "bar")); 

    for (auto f : collection) { 
     f("foo"); 
    } 

    return 0; 
}