2009-02-09 13 views
80

Je n'aime avoir des boîtes magiques dispersés sur tout mon code ... Comment exactement ces deux classes travaillent pour permettre essentiellement une fonction à être mis en correspondance à un objet de fonction, même si la fonction <> a un paramètre complètement différent pour celui que im passant à boost::bindcomment boost :: fonction et boost :: bind travail

Il fonctionne même avec différentes conventions d'appel (c.-à-méthodes membres sont __thiscall sous VC, mais les fonctions « normales » sont généralement __cdecl ou __stdcall pour ceux qui doivent être compatible avec C.

+0

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

+1

pas vraiment - cette question est sur la liaison et la fonction –

+0

Oui et donc cela laisse toujours la question de savoir comment peut lier la carte void MyClass: DoSomething (std :: chaîne str, nombre entier) à boost :: fonction via bind (& MyClass :: DoSomething, instance, "Bonjour le monde", _1) –

Répondre

94

boost::function permet n'importe quoi avec un operator() avec la bonne signature à être liée en tant que paramètre, et le résultat de votre liaison peut être appelé avec un paramètre int, de sorte qu'il peut être lié à function<void(int)>.

Voilà comment cela fonctionne (cette description s'applique aussi bien pour std::function):

boost::bind(&klass::member, instance, 0, _1) retourne un objet comme celui-ci

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

où le return_type et int sont déduits de la signature de klass::member, et pointeur de fonction et paramètre lié sont en fait stockés dans l'objet, mais ce n'est pas important

Maintenant, boost::function fait ne pas faire de 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 est appelable selon votre signature et appellera l'objet. Si c'est impossible, c'est une erreur de compilation.

boost::function est en fait un objet de ce type:

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

où le return_type et argument_type sont extraits de Sig, et f est allouée dynamiquement sur le tas. Cela est nécessaire pour autoriser des objets complètement indépendants avec des tailles différentes à boost::function.

function_impl est juste 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 a un pour chaque type d'objet que vous attribuez à 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 que dans votre cas, l'affectation à stimuler la fonction:

  1. instancie un type function_impl_concrete<void(int), unspecified_type> (qui est la compilation, bien sûr)
  2. crée un nouvel objet de ce type sur le tas
  3. attribue cet objet à l'élément f de boost :: fonction

Lorsque vous appelez l'objet de fonction, il appelle la fonction virtuelle de son objet de mise en œuvre, qui dirigera l'appel à votre fonction d'origine.AVIS DE NON-RESPONSABILITÉ: Notez que les noms de cette explication sont délibérément constitués. Toute ressemblance avec de vraies personnes ou personnages ... vous le savez. Le but était d'illustrer les principes.

+0

donc le contenu de struct unspecified_type (c'est-à-dire le code de la fonction operator()) est-il généré par les arguments passé à boost :: bind au cas par cas pour autoriser n'importe quelle combinaison et nombre d'arguments? –

+1

Non, il y a des templates de operator() qui gèrent toutes les arities (et différents arguments de templates gèrent les combinaisons) – jpalecek

+0

Dans le dernier bloc de code il lit: 'arg0) const = 0 {return ...' ... j'ai jamais vu ça avant. J'ai trouvé un exemple non fonctionnel dans un forum où un message de suivi lié à la faq C++ expliquait qu'une fonction virtuelle pure pouvait avoir un corps, mais je ne peux obtenir aucun code pour compiler en utilisant une telle syntaxe (clang & gcc). –