Je n'aime pas avoir des boîtes magiques dispersées dans tout mon code ... comment fonctionnent exactement ces deux classes pour permettre à n'importe quelle fonction d'être mappée à un objet fonction même si la fonction <> a un paramètre complètement différent de celui que je passe à boost::bind
Il fonctionne même avec différentes conventions d'appel (c'est-à-dire que les méthodes membres sont __thiscall
sous VC, mais les fonctions "normales" sont généralement __cdecl
ou __stdcall
pour ceux qui doivent être compatibles avec C.
boost::function
Permet à tout ce qui a une operator()
avec la bonne signature d'être lié comme paramètre, et le résultat de votre liaison peut être appelé avec un paramètre int
, donc il peut être lié à function<void(int)>
.
Voici comment cela fonctionne (cette description s'applique également à std::function
):
boost::bind(&klass::member, instance, 0, _1)
renvoie un objet comme celui-ci
struct unspecified_type
{
... some members ...
return_type operator()(int i) const { return instance->*&klass::member(0, i);
}
où return_type
et int
sont déduits de la signature de klass::member
, et le pointeur de fonction et le paramètre lié sont en fait stockés dans l'objet, mais ce n'est pas important
Maintenant, boost::function
N'effectue aucune vérification de type: il prendra tout objet et toute signature que vous fournissez dans son paramètre de modèle, et créera un objet qui peut être appelé en fonction de votre signature et appelle l'objet. Si c'est impossible, c'est une erreur de compilation.
boost::function
Est en fait un objet comme celui-ci:
template <class Sig>
class function
{
function_impl<Sig>* f;
public:
return_type operator()(argument_type arg0) const { return (*f)(arg0); }
};
où return_type
et argument_type
sont extraits de Sig
et f
est alloué dynamiquement sur le tas. Cela est nécessaire pour permettre à des objets complètement indépendants de différentes tailles de se lier à boost::function
.
function_impl
N'est qu'une classe abstraite
template <class Sig>
class function_impl
{
public:
virtual return_type operator()(argument_type arg0) const=0;
};
La classe qui fait tout le travail est une classe concrète dérivée de boost::function
. Il y en a un pour chaque type d'objet que vous affectez à 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); }
};
Cela signifie dans votre cas, la fonction d'attribution de boost:
function_impl_concrete<void(int), unspecified_type>
(c'est le temps de compilation, bien sûr)Lorsque vous appelez l'objet fonction, il appelle la fonction virtuelle de son objet d'implémentation, qui dirigera l'appel vers votre fonction d'origine.
AVERTISSEMENT: Notez que les noms dans cette explication sont délibérément inventés. Toute ressemblance avec de vraies personnes ou personnages ... vous le savez. Le but était d'illustrer les principes.