2009-02-09 21 views
80

No me gusta tener cajas mágicas dispersas por todo mi código ... ¿Cómo funcionan exactamente estas dos clases para permitir básicamente que cualquier función se asigne a un objeto de función incluso si la función <> tiene un parámetro completamente diferente al que más im pasando a boost::bindcómo boost :: function and boost :: bind work

incluso trabaja con diferentes convenciones de llamada (es decir, métodos miembros son __thiscall bajo VC, pero las funciones "normales" son generalmente __cdecl o __stdcall para aquellos que necesitan ser compatible con C.

+0

Dupe: http://stackoverflow.com/questions/112738/how-does-boost-bind-work-behind-the-scenes-in-general –

+1

no realmente - esta pregunta es sobre enlace y función –

+0

Sí y por lo tanto, aún queda la cuestión de cómo enlazar map void MyClass: DoSomething (std :: string str, int number) para impulsar :: function mediante bind (& MyClass :: DoSomething, instancia, "Hello World", _1) –

Respuesta

94

boost::function permite cualquier cosa con operator() con la firma correcta para vincularse como parámetro, y el resultado de su enlace se puede invocar con un parámetro int, por lo que puede vincularse al function<void(int)>.

Esto es cómo funciona (esta descripción se aplica por igual a std::function):

boost::bind(&klass::member, instance, 0, _1) devuelve un objeto como éste

struct unspecified_type 
{ 
    ... some members ... 
    return_type operator()(int i) const { return instance->*&klass::member(0, i); 
} 

donde el return_type y int se infiere a partir de la firma del klass::member, y el El puntero a la función y el parámetro enlazado están de hecho almacenados en el objeto, pero eso no es importante

Ahora, boost::function hace no hacer ninguna verificación de tipo: tomará cualquier objeto y cualquier firma que proporcione en su parámetro de plantilla, y creará un objeto que se pueda llamar de acuerdo con su firma y llame al objeto. Si eso es imposible, es un error de compilación.

boost::function es en realidad un objeto como este:

template <class Sig> 
class function 
{ 
    function_impl<Sig>* f; 
public: 
    return_type operator()(argument_type arg0) const { return (*f)(arg0); } 
}; 

donde el return_type y argument_type se extraen de Sig, y f se asigna dinámicamente en el montón. Eso es necesario para permitir que objetos completamente no relacionados con diferentes tamaños se unan a boost::function.

function_impl es sólo una clase abstracta

template <class Sig> 
class function_impl 
{ 
public: 
    virtual return_type operator()(argument_type arg0) const=0; 
}; 

La clase que hace todo el trabajo, es una clase concreta derivada de boost::function. Hay uno para cada tipo de objeto que se asigna a boost::function

template <class Sig, class Object> 
class function_impl_concrete : public function_impl<Sig> 
{ 
    Object o 
public: 
    virtual return_type operator()(argument_type arg0) const=0 { return o(arg0); } 
}; 

Eso significa, en su caso, la cesión a estimular la función:

  1. instancia un tipo function_impl_concrete<void(int), unspecified_type> (que es el tiempo de compilación, por supuesto)
  2. crea un nuevo objeto de ese tipo en el montón
  3. asigna este objeto para el miembro f de la función impulso ::

Cuando llama al objeto de función, llama a la función virtual de su objeto de implementación, que dirigirá la llamada a su función original.

DESCARGO DE RESPONSABILIDAD: Tenga en cuenta que los nombres en esta explicación se componen deliberadamente. Cualquier parecido con personas o personajes reales ... lo sabes. El propósito fue ilustrar los principios.

+0

así es el contenido de struct unspecified_type (es decir, el código en la función operator()) generado básicamente a partir de los argumentos anteriores para impulsar :: bind en una base de caso por caso para permitir cualquier combinación y número de argumentos? –

+1

No, hay plantillas de operador() que manejan todas las aries (y diferentes argumentos de plantilla manejan las combinaciones) – jpalecek

+0

En el último bloque de código se lee: 'arg0) const = 0 {return ...' ... He nunca antes visto eso. Encontré un ejemplo que no funcionaba en un foro donde un mensaje de seguimiento vinculado a C++ faq explicaba que una función virtual pura podía tener un cuerpo, pero no puedo obtener ningún código para compilar usando una sintaxis como esa (clang & gcc). –

Cuestiones relacionadas