2008-11-11 11 views
21

quiere pasar boost :: bind a un método que espera un puntero de función simple (misma firma).demote boost :: function a un puntero de función simple

typedef void TriggerProc_type(Variable*,void*); 
void InitVariable(TriggerProc_type *proc); 
boost::function<void (Variable*, void*)> triggerProc ... 
InitVariable(triggerProc); 

error C2664: 'InitVariable' : cannot convert parameter 1 from 
'boost::function<Signature>' to 'void (__cdecl *)(type *,void *)' 

puedo evitar el almacenamiento de un impulso :: función y sólo tiene que pasar el funtor unido directamente, pero luego me sale error similar:

error C2664: 'blah(void (__cdecl *)(type *,void *))' : cannot convert parameter 
1 from 'boost::_bi::bind_t<R,F,L>' to 'void (__cdecl *)(type *,void *)' 

Respuesta

39

nadie se ha dado cuenta de que el accepted answer sólo funciona con los casos triviales? La única forma en que la función <> :: target() devolverá un objeto que puede vincularse a una devolución de llamada C, es si se construyó con un objeto que puede vincularse a una devolución de llamada C. Si ese es el caso, entonces podría haberlo enlazado directamente y omitido toda la función <> sin sentido para empezar.

Si lo piensas bien, no hay ninguna solución mágica para esto. Una devolución de llamada al estilo C se almacena como un único puntero que apunta a un código ejecutable. Cualquier función boost :: no trivial :: <> va a necesitar al menos dos punteros: uno para el código ejecutable y el otro para los datos necesarios para configurar la llamada (por ejemplo, el puntero 'this', en el caso de un miembro vinculado) función).

La forma correcta de usar boost :: function y boost :: bind with C callbacks es crear una función shim que satisfaga la firma de devolución de llamada, averigüe qué función <> llamar y la llama. Por lo general, las devoluciones de llamadas C tendrán algún tipo de vacío * para 'datos de usuario'; ahí es donde se Stash su función de puntero:

typedef void (*CallbackType)(int x, void* user_data); 
void RegisterCallback(CallbackType cb, void* user_data); 

void MyCallback(int x, void* userData) { 
    boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData); 
    pfn(x); 
} 

boost::function<void(int)> fn = boost::bind(myFunction(5)); 
RegisterCallback(MyCallback, &fn); 

Por supuesto, si su firma de devolución de llamada no incluye algún tipo de puntero de datos de usuario, estás de suerte. Pero cualquier devolución de llamada que no incluya un puntero de datos de usuario ya no se puede utilizar en la mayoría de los escenarios del mundo real y debe volverse a escribir.

+1

'boost :: function pfn = static_cast > (userData); '¿debería usar boost :: function * en su lugar o habrá error de compilación? – Gohan

+0

@Gohan sí, esa fue la intención del autor. Arreglaré la publicación ... – Yann

11

Creo que desea utilizar la función de miembro de destino() de boost :: function (¿no es un bocado?)

#include <boost/function.hpp> 
#include <iostream> 

int f(int x) 
{ 
    return x + x; 
} 

typedef int (*pointer_to_func)(int); 

int 
main() 
{ 
    boost::function<int(int x)> g(f); 

    if(*g.target<pointer_to_func>() == f) { 
    std::cout << "g contains f" << std::endl; 
    } else { 
    std::cout << "g does not contain f" << std::endl; 
    } 

    return 0; 
} 
0

¿Se puede conseguir trabajando con bind?

#include <boost/function.hpp> 
#include <boost/bind.hpp> 

void f(int x) 
{ 
    (void) x; 
    _asm int 3; 
} 

typedef void (*cb_t)(int); 

int main() 
{ 
    boost::function<void (int x)> g = boost::bind(f, 3); 
    cb_t cb = *g.target<cb_t>(); //target returns null 
    cb(1); 

    return 0; 
} 

actualización: De acuerdo, bien la intención es enlazar un método en una función-devolución de llamada. ¿y ahora que?

+0

la única manera de obtener datos en una devolución de llamada sin vincularla, es a través de un objeto libre –

3

can you get it working with bind?

cb_t cb = *g.target<cb_t>(); //target returns null 

Esto es by design. Básicamente, dado que bind devuelve un tipo completamente diferente, no hay forma de que esto funcione. Básicamente, un objeto proxy de enlace no se puede convertir a un puntero de función C (ya que no es uno: es un objeto de función). El tipo devuelto por boost::bind es complicado. El estándar actual de C++ no permite una buena forma de hacer lo que desea. C++ 0x será equipado con una expresión decltype que podría ser utilizado aquí para lograr algo como esto:

typedef decltype(bind(f, 3)) bind_t; 
bind_t target = *g.target<bind_t>(); 

Tenga en cuenta que esto podría o no podría funcionar. No tengo forma de probarlo.

+0

Bien, bien, la intención es vincular un método en una función de devolución de llamada. ¿y ahora que? –

+0

Básicamente, no puedes. No se usa 'boost :: bind' y' boost :: function'.El único recurso podría ser codificar la función requerida y recuperar un puntero a ella. –

+6

hombre, esto hubiera tomado 10s en python :( –

Cuestiones relacionadas