2010-04-29 10 views
6

Supongamos que tengo una función boost :: con una firma arbitraria llamada tipo CallbackType.¿Es posible usar boost :: bind para efectivamente concatenar funciones?

  • ¿Es posible utilizar boost::bind para componer una función que toma los mismos argumentos que la CallbackType pero llama a los dos funtores en la serie?

Estoy abierto a cualquier solución potencial, pero aquí hay un ...

... Ejemplo hipotético uso de algunos magic plantilla:

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

¿Se supone que 'magic' debe implementarse en términos de' bind'? ¿Cuál es el papel de 'bind' que se supone que es? Ciertamente, no estás vinculando nada a la devolución de llamada. – Potatoswatter

+0

'magic' sería quizás una plantilla que creara automáticamente un functor que tomara dos funtores como argumentos + todos los argumentos de' CallbackType' ... pero esto solo pretende ilustrar mi objetivo, no necesariamente ofrecer una solución realista. Estoy abierto a sugerencias drásticamente diferentes. – Catskul

+0

¿Estás tratando de componer un 'void (void)' con 'void (int, int, int)'? ¿O fue solo un error tipográfico? – MSN

Respuesta

8

Boost ya proporciona una forma de crear una secuencia de funciones enlazadas. Use 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); 

que va a crear un nuevo funtor, object. Cuando invoque ese functor con tres argumentos, a su vez llamará al mc.alert() antes de pasar esos argumentos al doIt. Los paréntesis son importantes.

Para que mi ejemplo anterior funcione, necesitaría alert para ser una función const. Si necesita ser no const, entonces pase un puntero a mc, o envuélvalo con boost::ref(mc). Y deberá usar Boost.Lambda's bind en lugar de Boost.Bind's; este último no es compatible con la función de Lambda: combinación de operadores (coma, en particular).

+0

¿cómo funcionaría esto con C++ 11 'std :: bind'? – 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. 
}; 

Boost utiliza un lazo gran cantidad de pirateo de preprocesadores para su vudú variad, y desafortunadamente no creo que proporcione un patrón o herramientas para parchear la cabeza, que es esencialmente lo que es.

+0

Parece que debería haber una manera más fácil, y tal vez mi ejemplo de hombre de paja va en la dirección completamente equivocada. Comenzar una recompensa, pero esto puede terminar marcado como la respuesta. – Catskul

Cuestiones relacionadas