web-dev-qa-db-fra.com

comment boost :: function et boost :: bind work

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.

81
Fire Lancer

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);
}

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); }
};

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:

  1. instancie un type function_impl_concrete<void(int), unspecified_type> (c'est le temps de compilation, bien sûr)
  2. crée un nouvel objet de ce type sur le tas
  3. assigne cet objet au membre f de boost :: function

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.

94
jpalecek