Zahlreiche C++-Bibliotheken, einschließlich der Standardbibliotheken, ermöglichen es Ihnen, Ihre Objekte für die Verwendung in den Bibliotheken anzupassen. Die Wahl ist oft zwischen einer Mitgliedsfunktion oder einer freien Funktion im gleichen Namensraum.
Ich würde gerne wissen, Mechanik und Konstrukte der Bibliothek-Code verwendet, um einen Aufruf zu versenden, die eine dieser "Erweiterung" Funktionen aufrufen wird, ich weiß, dass diese Entscheidung während der Kompilierzeit stattfinden muss und Vorlagen beinhaltet. Der folgende Laufzeit-Psuedocode ist nicht möglich/unsinnig, die Gründe liegen außerhalb des Rahmens dieser Frage.
if Class A has member function with signature FunctionSignature
choose &A.functionSignature(...)
else if NamespaceOfClassA has free function freeFunctionSignature
choose freeFunctionSignature(...)
else
throw "no valid extension function was provided"
Der obige Code sieht aus wie Laufzeitcode :/. Also, wie findet die Bibliothek heraus, in welchem Namespace sich eine Klasse befindet, wie erkennt sie die drei Bedingungen, welche anderen Fallstricke gibt es, die vermieden werden müssen.
Die Motivation für meine Frage ist, dass ich die Dispatch-Blöcke in Bibliotheken finden und die Konstrukte in meinem eigenen Code verwenden kann. Detaillierte Antworten werden also helfen.
!!!KOPFGELD ZU GEWINNEN!!
Ok, so dass nach der Antwort von Steve (und die Kommentare) ADL und SFINAE sind die wichtigsten Konstrukte für die Verdrahtung der Versand zur Kompilierungszeit. Ich habe meinen Kopf arround ADL (primitiv) und SFINAE (wieder rudimentär). Aber ich weiß nicht, wie sie zusammen in der Art und Weise orchistrieren, wie ich denke, sie sollten.
Ich möchte ein anschauliches Beispiel dafür sehen, wie diese beiden Konstrukte zusammengefügt werden können, so dass eine Bibliothek zur Kompilierzeit wählen kann, ob sie eine vom Benutzer bereitgestellte Mitgliedsfunktion in einem Objekt oder eine vom Benutzer bereitgestellte freie Funktion im Namensraum desselben Objekts aufrufen soll. Dies sollte nur unter Verwendung der beiden obigen Konstrukte geschehen, ohne irgendeine Art von Laufzeitversand.
Nehmen wir an, das betreffende Objekt heißt NS::Car
, und dieses Objekt muss das Verhalten von MoveForward(int units)
als eine Mitgliedsfunktion vonc. Wenn das Verhalten aus dem Namespace des Objekts übernommen werden soll, wird es wahrscheinlich wie folgt aussehen MoveForward(const Car & car_, int units)
. Definieren wir die Funktion, die versenden soll mover(NS::direction d, const NS::vehicle & v_)
wobei direction ein Enum ist und v_ eine Basisklasse von NS::car
.