2012-09-09 14 views
26

Mam funkcję void wewnątrz klasy. W starym C++ zrobiłem funkcję statyczną biorąc nazwę klasy jako parametr i miałem własną klasę, która wzięła funkcję statycznej pustki + pustkę * dla mnie, aby łatwo ją nazwać.Wywołania zwrotne w stylu C++ 11?

Jednak to czuje się w starej szkole. Nie ma też szablonów, co sprawia, że ​​mogę robić więcej. Co jest bardziej nowoczesny sposób tworzenia zwrotnych do myclassVar.voidReturnVoidParamFunc

+0

„To również nie jest na matrycy, który czuje się jak mogę robić więcej” Kod C++ nie musi być szablonem na C++. –

+0

@NicolBolas uczciwie to rozwiązanie wykorzystało jeden i działa * naprawdę * dobrze (lambdas) –

Odpowiedz

53

Zastosowanie std::function and lambdas (or std::bind()) przechowywać callables:

#include <functional> 
#include <iostream> 


class Test 
{ 
public: 
     void blah() { std::cout << "BLAH!" << std::endl; } 
}; 

class Bim 
{ 
public: 
     void operator()(){ std::cout << "BIM!" << std::endl; } 
}; 

void boum() { std::cout << "BOUM!" << std::endl; } 


int main() 
{ 
    // store the member function of an object: 
    Test test; 
    std::function< void() > callback = std::bind(&Test::blah, test); 
    callback(); 

    // store a callable object (by copy) 
    callback = Bim{}; 
    callback(); 

    // store the address of a static function 
    callback = &boum; 
    callback(); 

    // store a copy of a lambda (that is a callable object) 
    callback = [&]{ test.blah(); }; // often clearer -and not more expensive- than std::bind() 
    callback(); 
}  

Wynik:

BLAH!

BIM!

BOUM!

BLAH!

kompiluje i uruchomić: http://ideone.com/T6wVp

std::function mogą być wykorzystywane jako dowolny copyiable przedmiotów, aby czuć się swobodnie przechowywać go gdzieś jako zwrotnego, jak na członka obiektu. Oznacza to również, że można go dowolnie umieszczać w standardowych pojemnikach, takich jak std::vector< std::function< void() > >.

Należy również pamiętać, że odpowiednik boost::function and boost::bind jest dostępny od lat.

+1

@Hauleth Nie powiedziałem, że to skomplikowane, powiedziałem, że jest jaśniejsze z lambdą. Zapamiętywanie kolejności argumentów (w szczególności gdy pojawia się niejasny błąd kompilacji, jeśli jest to zła kolejność) sprawia, że ​​jest to "trudniejsze" niż po prostu napisanie połączenia jawnie jak w lambda. – Klaim

+1

Wznowienie dla efektów dźwiękowych! – Ignorant

+0

Wiem, że pisałeś o tym dawno temu, ale potrzebuję tu wyjaśnienia: pierwsze 3 wiersze w głównym miejscu, w którym wiążesz instancję klasy jako argument do samej funkcji klasy, działają, ponieważ kompilator robiłby to również potajemnie, gdy normalnie dzwonimy. funkcja członka klasy, prawda? Tak więc kompilator dodaje odwołanie do instancji jako * this * argument do każdej funkcji jako pierwszy parametr! Czy możesz potwierdzić moje założenie? – binaryguy

5

Na przykład przekazując parametry do C++ 11 zwrotnego za pomocą Lambda i wektor, zobacz http://ideone.com/tcBCeO lub poniżej:

class Test 
{ 
public: 
     Test (int testType) : m_testType(testType) {}; 
     void blah() { std::cout << "BLAH! " << m_testType << std::endl; } 
     void blahWithParmeter(std::string p) { std::cout << "BLAH1! Parameter=" << p << std::endl; } 
     void blahWithParmeter2(std::string p) { std::cout << "BLAH2! Parameter=" << p << std::endl; } 

     private: 
     int m_testType; 

}; 

class Bim 
{ 
public: 
     void operator()(){ std::cout << "BIM!" << std::endl; } 
}; 

void boum() { std::cout << "BOUM!" << std::endl; } 


int main() 
{ 
    // store the member function of an object: 
    Test test(7); 
    //std::function< void() > callback = std::bind(&Test::blah, test); 
    std::function< void() > callback = std::bind(&Test::blah, test); 
    callback(); 

    // store a callable object (by copy) 
    callback = Bim{}; 
    callback(); 

    // store the address of a static function 
    callback = &boum; 
    callback(); 

    // store a copy of a lambda (that is a callable object) 
    callback = [&]{ test.blah(); }; // might be clearer than calling std::bind() 
    callback(); 

    // example of callback with parameter using a vector 
    typedef std::function<void(std::string&)> TstringCallback; 

    std::vector <TstringCallback> callbackListStringParms; 
    callbackListStringParms.push_back([&] (const std::string& tag) {  test.blahWithParmeter(tag); }); 
    callbackListStringParms.push_back([&] (const std::string& tag) { test.blahWithParmeter2(tag); }); 

    std::string parm1 = "parm1"; 
    std::string parm2 = "parm2"; 
    int i = 0; 
    for (auto cb : callbackListStringParms) 
    { 
     ++i; 
     if (i == 1) 
      cb(parm1); 
     else 
      cb(parm2); 

    } 
}  
Powiązane problemy