wie boost :: function und boost :: bind funktionieren

83

Ich mag es nicht, wenn Magic Boxes über meinen Code verteilt sind ... wie genau funktionieren diese beiden Klassen, damit grundsätzlich jede Funktion einem Funktionsobjekt zugeordnet werden kann, selbst wenn die Funktion <> einen völlig anderen Parametersatz hat als die, an die ich übergebe boost::bind

Es funktioniert sogar mit verschiedenen Aufrufkonventionen (dh Mitgliedsmethoden stehen __thiscallunter VC, aber "normale" Funktionen sind im Allgemeinen __cdecloder __stdcallfür diejenigen, die mit C kompatibel sein müssen.

Fire Lancer
quelle
1
nicht wirklich - diese Frage handelt von Bindung und Funktion
1800 INFORMATION
Ja, und daher bleibt immer noch die Frage, wie Map void MyClass: DoSomething (std :: string str, int number) gebunden werden kann, um :: function <void (int)> über bind (& MyClass :: DoSomething, Instanz, "Hello World ", _1)
Fire Lancer
2
20.000 Besuche heilige Kuh dies muss auf der Boost- Titelseite sein!
Unixman83

Antworten:

95

boost::functionErmöglicht operator()das Binden von Elementen mit der richtigen Signatur als Parameter, und das Ergebnis Ihrer Bindung kann mit einem Parameter aufgerufen werden int, sodass es an gebunden werden kann function<void(int)>.

So funktioniert es (diese Beschreibung gilt gleichermaßen für std::function):

boost::bind(&klass::member, instance, 0, _1) gibt ein Objekt wie dieses zurück

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

wo die return_typeund intaus der Signatur von abgeleitet klass::memberwerden und der Funktionszeiger und der gebundene Parameter tatsächlich im Objekt gespeichert sind, aber das ist nicht wichtig

Jetzt wird boost::functionkeine Typprüfung durchgeführt: Es werden alle Objekte und Signaturen verwendet, die Sie in ihrem Vorlagenparameter angegeben haben, und es wird ein Objekt erstellt, das gemäß Ihrer Signatur aufrufbar ist und das Objekt aufruft. Wenn dies nicht möglich ist, liegt ein Kompilierungsfehler vor.

boost::function ist eigentlich ein Objekt wie dieses:

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

Dabei werden die return_typeund argument_typeextrahiert Sigund fdynamisch auf dem Heap zugewiesen. Dies ist erforderlich, damit völlig unabhängige Objekte mit unterschiedlichen Größen gebunden werden können boost::function.

function_impl ist nur eine abstrakte Klasse

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

Die Klasse, die die ganze Arbeit erledigt, ist eine konkrete Klasse, von der abgeleitet wird boost::function. Für jeden Objekttyp, den Sie zuweisen, gibt es einenboost::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); }
};

Das bedeutet in Ihrem Fall die Zuordnung zur Boost-Funktion:

  1. instanziiert einen Typ function_impl_concrete<void(int), unspecified_type>(das ist natürlich die Kompilierungszeit)
  2. Erstellt ein neues Objekt dieses Typs auf dem Heap
  3. weist dieses Objekt dem f-Mitglied von boost :: function zu

Wenn Sie das Funktionsobjekt aufrufen, ruft es die virtuelle Funktion seines Implementierungsobjekts auf, wodurch der Aufruf an Ihre ursprüngliche Funktion geleitet wird.

HAFTUNGSAUSSCHLUSS: Beachten Sie, dass die Namen in dieser Erklärung absichtlich erfunden sind. Jede Ähnlichkeit mit realen Personen oder Charakteren ... Sie wissen es. Ziel war es, die Prinzipien zu veranschaulichen.

jpalecek
quelle
Wird der Inhalt von struct unspecified_type (dh der Code in der operator () -Funktion) im Wesentlichen aus den vergangenen Argumenten generiert, um :: bind von Fall zu Fall zu verstärken, um eine beliebige Kombination und Anzahl von Argumenten zu ermöglichen?
Fire Lancer
1
Nein, es gibt Vorlagen von operator (), die alle Aritäten behandeln (und verschiedene Vorlagenargumente behandeln die Kombinationen)
jpalecek
Im letzten Codeblock heißt es: arg0) const=0 { return...... das habe ich noch nie gesehen. Ich habe ein nicht funktionierendes Beispiel in einem Forum gefunden, in dem eine mit der C ++ - FAQ verknüpfte Follow-up-Nachricht erklärt, dass eine reine virtuelle Funktion einen Body haben könnte, aber ich kann keinen Code zum Kompilieren mit einer solchen Syntax (clang & gcc) erhalten.
Brian Vandenberg
Ich sollte meine Frage leicht klären: Einem reinen virtuellen kann ein Körper gegeben werden, wenn er =0;mit dem später gegebenen Körper deklariert wird (z. B. void Base::Blah() { /* ... */ }) ... Ich frage speziell nach der oben verwendeten Notation; Ich vermute, es ist nur ein Tippfehler.
Brian Vandenberg
@BrianVandenberg: Ich denke, es ist standardkonform, obwohl es ziemlich sinnlos ist.
Mooing Duck