No me gusta tener cajas mágicas esparcidas por todo mi código ... ¿cómo funcionan exactamente estas dos clases para permitir que básicamente cualquier función se asigne a un objeto de función, incluso si la función <> tiene un parámetro completamente diferente al que estoy pasando? boost::bind
Incluso funciona con diferentes convenciones de llamada (es decir, los métodos miembro están __thiscall
bajo VC, pero las funciones "normales" son generalmente __cdecl
o __stdcall
para aquellas que necesitan ser compatibles con C.
c++
boost
boost-bind
boost-function
Lancer de fuego
fuente
fuente
Respuestas:
boost::function
permite que cualquier cosa con unaoperator()
con la firma correcta se vincule como parámetro, y el resultado de su vinculación se puede llamar con un parámetroint
, por lo que se puede vincular afunction<void(int)>
.Así es como funciona (esta descripción se aplica por igual
std::function
):boost::bind(&klass::member, instance, 0, _1)
devuelve un objeto como estestruct unspecified_type { ... some members ... return_type operator()(int i) const { return instance->*&klass::member(0, i); }
donde
return_type
yint
se infieren de la firma deklass::member
, y el puntero de la función y el parámetro vinculado se almacenan de hecho en el objeto, pero eso no es importanteAhora,
boost::function
no realiza ninguna verificación de tipo: tomará cualquier objeto y cualquier firma que proporciones en su parámetro de plantilla, y creará un objeto que se pueda llamar de acuerdo con tu firma y llamará 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
yargument_type
se extraen deSig
, yf
se asigna dinámicamente en el montón. Eso es necesario para permitir que se unan objetos completamente no relacionados con diferentes tamañosboost::function
.function_impl
es solo una clase abstractatemplate <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 asigneboost::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 asignación para impulsar la función:
function_impl_concrete<void(int), unspecified_type>
(eso es tiempo de compilación, por supuesto)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 inventan deliberadamente. Cualquier parecido con personas o personajes reales ... lo sabes. El propósito era ilustrar los principios.
fuente
arg0) const=0 { return...
... Nunca había visto eso antes. Encontré un ejemplo que no funcionaba en un foro donde un mensaje de seguimiento vinculado a las preguntas frecuentes de C ++ explicando que una función virtual pura podría tener un cuerpo, pero no puedo obtener ningún código para compilar usando una sintaxis como esa (clang & gcc).=0;
con el cuerpo dado más adelante (por ejemplo,void Base::Blah() { /* ... */ }
) ... Estoy preguntando específicamente sobre la notación utilizada anteriormente; Supongo que es solo un error tipográfico.