2010-04-29 17 views
6

Załóżmy, że mam funkcję boost :: function z arbitralnym sygnaturą o nazwie typ: CallbackType.Czy można użyć funkcji boost :: bind, aby skutecznie łączyć funkcje?

  • Czy jest możliwe aby użyć boost::bind komponować funkcję, która pobiera te same argumenty jak CallbackType ale wywołuje dwa funktory z rzędu?

Jestem otwarty na wszelkie potencjalne rozwiązanie, ale tutaj jest ...

... Hipotetyczny przykład stosując pewne magic szablonu:

Template<typename CallbackType> 
class MyClass 
{ 
    public: 
     CallbackType doBoth; 

     MyClass(CallbackType callback) 
     { 
      doBoth = bind(magic<CallbackType>, 
          protect(bind(&MyClass::alert, this)), 
           protect(callback)     ); 
     } 

     void alert() 
     { 
      cout << "It has been called\n"; 
     } 
}; 

void doIt(int a, int b, int c) 
{ 
    cout << "Doing it!" << a << b << c << "\n"; 
} 

int main() 
{ 
    typedef boost::function<void (int, int, int)> CallbackType; 

    MyClass<CallbackType> object(boost::bind(doIt)); 

    object.doBoth(); 

    return 0; 
} 
+0

Czy 'magia' ma być zaimplementowana w znaczeniu" bind "? Jaka jest rola "binda"? Z pewnością nie wiążisz niczego do wywołania zwrotnego. – Potatoswatter

+0

'magic' to może być szablon, który automatycznie utworzył funktor, który wziął dwa funktory jako argumenty + wszystkie argumenty' CallbackType' ... ale ma to jedynie zilustrować mój cel, niekoniecznie oferując realistyczne rozwiązanie. Jestem otwarty na drastycznie różne sugestie. – Catskul

+0

Czy próbujesz skomponować 'void (void)' z 'void (int, int, int)'? A może to tylko literówka? – MSN

Odpowiedz

8

Zwiększ już zapewnia sposób tworzenia sekwencji powiązanych funkcji. Użyj Lambda's comma operator.

using namespace boost::lambda; 
MyClass mc; 
CallbackType object = (bind(&MyClass::alert, mc), bind(doIt, _1, _2, _3)); 
object(1, 2, 3); 

To spowoduje utworzenie nowego funktora, object. Gdy wywołasz ten funktor z trzema argumentami, on z kolei wywoła mc.alert() przed przekazaniem tych argumentów do doIt. Nawiasy są ważne.

Dla mojego przykładu powyżej do pracy, musisz alert, aby być funkcją const. Jeśli ma być niestały, przepuść wskaźnik do mc lub zawiń go w boost::ref(mc). I będziesz musiał użyć Boost.Lambdy za bind zamiast Boost.Bind's; ta ostatnia nie jest zgodna z operatorami Lambdy łączącymi funkcje (w szczególności przecinek).

+0

jak by to działało z 'std :: bind 'w C++ 11? – Valerij

1
template< class Callback > 
struct pre_caller { 
    Callback c; 

    pre_caller(Callback in_c) : c(in_c) {} 

    void alert() {} // or an instance of a functor 

    operator() 
    { alert(); c(); } 

    template< class T1 > 
    operator(T1 a) // not sure if/what qualification to add to a 
    { alert(); c(a); } // or whether to attempt to obtain from 
         // function_traits<Callback>? 
    template< class T1, class T2 > 
    operator(T1 a, T2 b) 
    { alert(); c(a, b); } 

    template< class T1, class T2, class T3 > 
    operator(T1 a, T2 b, T3 c) 
    { alert(); c(a, b, c); } 

    // ad nauseam... and I mean nausea, maybe read up on Boost Preprocessor. 
}; 

doładowania Bind używa dużo hakowania preprocesora dla jego variadic voodoo, i niestety nie sądzę, że zapewnia wzór lub narzędzia do łatania głowy, co jest w istocie tym, co to jest.

+0

Wygląda na to, że powinien istnieć łatwiejszy sposób, a może mój przykład słomianego człowieka idzie w zupełnie niewłaściwym kierunku. Rozpoczęcie bounty, ale może to oznaczać jako odpowiedź. – Catskul

Powiązane problemy