Ich möchte in der Lage sein, eine C ++ - Klasse auf ihren Namen, Inhalt (dh Mitglieder und ihre Typen) usw. zu überprüfen. Ich spreche hier von nativem C ++, nicht von verwaltetem C ++, das reflektiert wird. Mir ist klar, dass C ++ mit RTTI nur begrenzte Informationen liefert. Welche zusätzlichen Bibliotheken (oder andere Techniken) könnten diese Informationen liefern?
c++
reflection
templates
sfinae
Nick
quelle
quelle
Antworten:
Was Sie tun müssen, ist, dass der Präprozessor Reflexionsdaten über die Felder generiert. Diese Daten können als verschachtelte Klassen gespeichert werden.
Um es einfacher und sauberer zu machen, es in den Präprozessor zu schreiben, verwenden wir zunächst einen typisierten Ausdruck. Ein typisierter Ausdruck ist nur ein Ausdruck, der den Typ in Klammern setzt. Also anstatt zu schreiben,
int x
wirst du schreiben(int) x
. Hier sind einige nützliche Makros, die bei getippten Ausdrücken helfen:Als nächstes definieren wir ein
REFLECTABLE
Makro, um die Daten für jedes Feld (plus das Feld selbst) zu generieren. Dieses Makro wird folgendermaßen aufgerufen:Mit Boost.PP iterieren wir also über jedes Argument und generieren die Daten wie folgt :
Dadurch wird eine Konstante generiert
fields_n
, die die Anzahl der reflektierbaren Felder in der Klasse darstellt. Dann ist es dasfield_data
für jedes Feld spezialisiert. Es befreundet auch diereflector
Klasse, so dass es auf die Felder zugreifen kann, auch wenn sie privat sind:Um nun über die Felder zu iterieren, verwenden wir das Besuchermuster. Wir erstellen einen MPL-Bereich von 0 bis zur Anzahl der Felder und greifen auf die Felddaten an diesem Index zu. Anschließend werden die Felddaten an den vom Benutzer bereitgestellten Besucher weitergeleitet:
Jetzt für den Moment der Wahrheit setzen wir alles zusammen. So können wir eine
Person
Klasse definieren , die reflektierbar ist:Hier ist eine verallgemeinerte
print_fields
Funktion, die die Reflexionsdaten verwendet, um über die Felder zu iterieren:Ein Beispiel für die Verwendung der
print_fields
mit der reflektierbarenPerson
Klasse:Welche Ausgänge:
Und voila, wir haben gerade die Reflexion in C ++ in weniger als 100 Codezeilen implementiert.
quelle
#define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple
und#define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__))
und ändern Sie die Definition von TYPEOF (x) in:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Es gibt zwei Arten des
reflection
Schwimmens.Dies ist mit C ++ nicht möglich.
So etwas ist mit C ++ möglich
template-tricks
. Verwenden Sie esboost::type_traits
für viele Dinge (z. B. um zu überprüfen, ob ein Typ ganzzahlig ist). Verwenden Sie zum Überprüfen der Existenz einer Mitgliedsfunktion die Option Ist es möglich, eine Vorlage zu schreiben, um die Existenz einer Funktion zu überprüfen? . Verwenden Sie einfaches SFINAE , um zu überprüfen, ob ein bestimmter verschachtelter Typ vorhanden ist .Wenn Sie eher nach Möglichkeiten suchen, um 1) zu erreichen, z. B. nach der Anzahl der Methoden einer Klasse oder nach der Zeichenfolgendarstellung einer Klassen-ID, dann gibt es leider keine Standard-C ++ - Methode, um dies zu tun. Sie müssen entweder verwenden
C ++ ist auf Geschwindigkeit ausgelegt. Wenn Sie eine Inspektion auf hoher Ebene wünschen, wie dies bei C # oder Java der Fall ist, muss ich Ihnen leider sagen, dass es keinen Weg ohne Aufwand gibt.
quelle
members<T>
die eine Liste aller Mitglieder von T zurückgibt. Wenn wir eine Laufzeitreflexion wünschen würden (dh RTTI gemischt mit Reflexion), würde der Compiler immer noch alle reflektierten Basistypen kennen. Es ist sehr wahrscheinlichmembers<T>(T&)
, dass T = std :: string niemals instanziiert wird, daher muss die RTTI für std :: string oder die abgeleiteten Klassen nicht enthalten sein.Und ich würde ein Pony lieben, aber Ponys sind nicht frei. :-p
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI ist das, was Sie bekommen werden. Reflexion, über die Sie nachdenken - vollständig beschreibende Metadaten zur Laufzeit verfügbar - ist für C ++ standardmäßig nicht vorhanden.
quelle
Die Informationen sind vorhanden - jedoch nicht in dem von Ihnen benötigten Format und nur, wenn Sie Ihre Klassen exportieren. Dies funktioniert unter Windows, ich weiß nichts über andere Plattformen. Verwenden Sie die Speicherklassenspezifizierer wie in:
Dadurch erstellt der Compiler die Klassendefinitionsdaten in die DLL / Exe. Aber es ist nicht in einem Format, das Sie leicht zum Nachdenken verwenden können.
In meiner Firma haben wir eine Bibliothek erstellt, die diese Metadaten interpretiert und es Ihnen ermöglicht, eine Klasse zu reflektieren, ohne zusätzliche Makros usw. in die Klasse selbst einzufügen. Damit können Funktionen wie folgt aufgerufen werden:
Dies bewirkt effektiv:
Die Funktion Invoke (this_pointer, ...) verfügt über variable Argumente. Wenn Sie eine Funktion auf diese Weise aufrufen, umgehen Sie natürlich Dinge wie const-security usw., sodass diese Aspekte als Laufzeitprüfungen implementiert werden.
Ich bin sicher, dass die Syntax verbessert werden könnte und bisher nur unter Win32 und Win64 funktioniert. Wir haben festgestellt, dass es sehr nützlich ist, automatische GUI-Schnittstellen zu Klassen zu haben, Eigenschaften in C ++ zu erstellen, zu und von XML zu streamen usw. Es ist nicht erforderlich, von einer bestimmten Basisklasse abzuleiten. Wenn es genügend Nachfrage gibt, könnten wir es vielleicht für die Veröffentlichung in Form bringen.
quelle
__declspec(dllexport)
und du kannst die Informationen aus einer .map-Datei abrufen, wenn du die Erstellung solcher während des Builds aktivierst.Die Reflexion wird von C ++ nicht sofort unterstützt. Das ist traurig, weil es Defensivtests zu einem Schmerz macht.
Es gibt verschiedene Ansätze zur Reflexion:
Der erste Link sieht am vielversprechendsten aus (verwendet Mods zum Klirren), der zweite beschreibt eine Reihe von Techniken, der dritte ist ein anderer Ansatz mit gcc:
http://www.donw.org/rfl/
https://bitbucket.org/dwilliamson/clreflect
https://root.cern.ch/how/how-use-reflex
Es gibt jetzt eine Arbeitsgruppe für C ++ - Reflexion. Siehe die Nachrichten für C ++ 14 @ CERN:
Bearbeiten 13/08/17:
Seit dem ursprünglichen Beitrag gab es eine Reihe möglicher Fortschritte bei der Reflexion. Im Folgenden finden Sie weitere Details und eine Diskussion zu den verschiedenen Techniken und dem Status:
Ein standardisierter Reflexionsansatz in C ++ sieht jedoch in naher Zukunft nicht vielversprechend aus, es sei denn, die Community hat ein viel größeres Interesse an der Unterstützung der Reflexion in C ++.
Im Folgenden wird der aktuelle Status basierend auf dem Feedback des letzten C ++ - Standardtreffens beschrieben:
Bearbeiten 13/12/2017
Die Reflexion scheint sich in Richtung C ++ 20 oder wahrscheinlicher zu bewegen, wahrscheinlich als TSR. Die Bewegung ist jedoch langsam.
Bearbeiten 15/09/2018
Ein Entwurf eines TS wurde zur Abstimmung an die nationalen Stellen geschickt.
Den Text finden Sie hier: https://github.com/cplusplus/reflection-ts
Bearbeiten 11/07/2019
Die Reflexion TS ist vollständig und kann im Sommer (2019) kommentiert und abgestimmt werden.
Der Meta-Template-Programmieransatz soll durch einen einfacheren Compile-Time-Code-Ansatz ersetzt werden (nicht im TS enthalten).
Bearbeiten 10/02/2020
Hier wird die Anforderung zur Unterstützung des Reflection TS in Visual Studio angefordert:
Vortrag des Autors David Sankel über die TS:
http://cppnow.org/history/2019/talks/
https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be
Bearbeiten 17. März 2020
Fortschritte bei der Reflexion werden gemacht. Einen Bericht aus dem Reisebericht des ISO C ++ - Komitees 2020-02 in Prag finden Sie hier:
Details dazu, was für C ++ 23 in Betracht gezogen wird, finden Sie hier (einschließlich eines kurzen Abschnitts über Reflexion):
Bearbeiten 4. Juni 2020
Jeff Preshing hat ein neues Framework namens "Plywood" veröffentlicht, das einen Mechanismus zur Laufzeitreflexion enthält. Weitere Details finden Sie hier:
Die Werkzeuge und der Ansatz scheinen die poliertesten und am einfachsten zu verwendenden zu sein.
quelle
Sie müssen sich ansehen, was Sie versuchen und ob RTTI Ihre Anforderungen erfüllt. Ich habe meine eigene Pseudoreflexion für einige ganz bestimmte Zwecke implementiert. Zum Beispiel wollte ich einmal flexibel konfigurieren können, was eine Simulation ausgeben würde. Es war erforderlich, den Klassen, die ausgegeben werden sollten, Boilerplate-Code hinzuzufügen:
Der erste Aufruf fügt dieses Objekt dem Filtersystem hinzu, das die
BuildMap()
Methode aufruft , um herauszufinden, welche Methoden verfügbar sind.In der Konfigurationsdatei können Sie dann Folgendes tun:
Durch einige Vorlagenmagie
boost
wird dies zur Laufzeit (wenn die Konfigurationsdatei gelesen wird) in eine Reihe von Methodenaufrufen übersetzt, sodass es ziemlich effizient ist. Ich würde dies nicht empfehlen, es sei denn, Sie müssen es wirklich tun, aber wenn Sie es tun, können Sie einige wirklich coole Sachen machen.quelle
Ich würde die Verwendung von Qt empfehlen .
Es gibt eine Open-Source-Lizenz sowie eine kommerzielle Lizenz.
quelle
Was versuchst du mit Reflexion zu tun?
Sie können die boost Typ Züge und TypeOf Bibliotheken als begrenzte Form der Kompilierung-Reflexion. Das heißt, Sie können die grundlegenden Eigenschaften eines an eine Vorlage übergebenen Typs überprüfen und ändern.
quelle
EDIT : CAMP wird nicht mehr gepflegt; Es stehen zwei Gabeln zur Verfügung:
CAMP ist eine MIT-lizenzierte Bibliothek (ehemals LGPL), die die C ++ - Sprache reflektiert. Es ist kein spezifischer Vorverarbeitungsschritt in der Kompilierung erforderlich, aber die Bindung muss manuell erfolgen.
Die aktuelle Tegesoft-Bibliothek verwendet Boost, aber es gibt auch einen Fork mit C ++ 11, für den Boost nicht mehr erforderlich ist .
quelle
Ich habe so etwas wie das getan, wonach Sie einmal gesucht haben, und obwohl es möglich ist, ein gewisses Maß an Reflexion und Zugriff auf übergeordnete Funktionen zu erhalten, sind die Wartungsprobleme möglicherweise nicht wert. Mein System wurde verwendet, um die UI-Klassen durch Delegierung vollständig von der Geschäftslogik zu trennen, ähnlich dem Objective-C-Konzept der Nachrichtenübermittlung und -weiterleitung. Die Möglichkeit besteht darin, eine Basisklasse zu erstellen, die Symbole (ich habe einen Zeichenfolgenpool verwendet, aber Sie können dies mit Aufzählungen tun, wenn Sie die Fehlerbehandlung bei Geschwindigkeit und Kompilierungszeit der vollständigen Flexibilität vorziehen) Funktionszeigern zuordnen kann (eigentlich nicht) reine Funktionszeiger, aber etwas Ähnliches wie Boost mit Boost.Function (auf das ich damals keinen Zugriff hatte). Sie können dasselbe für Ihre Mitgliedsvariablen tun, solange Sie über eine gemeinsame Basisklasse verfügen, die einen beliebigen Wert darstellen kann. Das gesamte System war eine unerschrockene Abzocke der Codierung und Delegierung von Schlüsselwerten, mit einigen Nebenwirkungen, die möglicherweise die Zeit wert waren, die erforderlich war, um jede Klasse, die das System verwendete, dazu zu bringen, alle ihre Methoden und Mitglieder mit rechtlichen Aufrufen abzustimmen : 1) Jede Klasse kann jede Methode für jede andere Klasse aufrufen, ohne Header einschließen oder gefälschte Basisklassen schreiben zu müssen, damit die Schnittstelle für den Compiler vordefiniert werden kann. und 2) Die Getter und Setter der Mitgliedsvariablen waren leicht threadsicher zu machen, da das Ändern oder Zugreifen auf ihre Werte immer über zwei Methoden in der Basisklasse aller Objekte erfolgte. Das gesamte System war eine unerschrockene Abzocke der Codierung und Delegierung von Schlüsselwerten, mit einigen Nebenwirkungen, die möglicherweise die Zeit wert waren, die erforderlich war, um jede Klasse, die das System verwendete, dazu zu bringen, alle ihre Methoden und Mitglieder mit rechtlichen Aufrufen abzustimmen : 1) Jede Klasse kann jede Methode für jede andere Klasse aufrufen, ohne Header einschließen oder gefälschte Basisklassen schreiben zu müssen, damit die Schnittstelle für den Compiler vordefiniert werden kann. und 2) Die Getter und Setter der Mitgliedsvariablen waren leicht threadsicher zu machen, da das Ändern oder Zugreifen auf ihre Werte immer über zwei Methoden in der Basisklasse aller Objekte erfolgte. Das gesamte System war eine unerschrockene Abzocke der Codierung und Delegierung von Schlüsselwerten, mit einigen Nebenwirkungen, die möglicherweise die Zeit wert waren, die erforderlich war, um jede Klasse, die das System verwendete, dazu zu bringen, alle ihre Methoden und Mitglieder mit rechtlichen Aufrufen abzustimmen : 1) Jede Klasse kann jede Methode für jede andere Klasse aufrufen, ohne Header einschließen oder gefälschte Basisklassen schreiben zu müssen, damit die Schnittstelle für den Compiler vordefiniert werden kann. und 2) Die Getter und Setter der Mitgliedsvariablen waren leicht threadsicher zu machen, da das Ändern oder Zugreifen auf ihre Werte immer über zwei Methoden in der Basisklasse aller Objekte erfolgte. 1) Jede Klasse kann jede Methode für jede andere Klasse aufrufen, ohne Header einschließen oder gefälschte Basisklassen schreiben zu müssen, damit die Schnittstelle für den Compiler vordefiniert werden kann. und 2) Die Getter und Setter der Mitgliedsvariablen waren leicht threadsicher zu machen, da das Ändern oder Zugreifen auf ihre Werte immer über zwei Methoden in der Basisklasse aller Objekte erfolgte. 1) Jede Klasse kann jede Methode für jede andere Klasse aufrufen, ohne Header einschließen oder gefälschte Basisklassen schreiben zu müssen, damit die Schnittstelle für den Compiler vordefiniert werden kann. und 2) Die Getter und Setter der Mitgliedsvariablen waren leicht threadsicher zu machen, da das Ändern oder Zugreifen auf ihre Werte immer über zwei Methoden in der Basisklasse aller Objekte erfolgte.
Es führte auch zu der Möglichkeit, einige wirklich seltsame Dinge zu tun, die in C ++ sonst nicht einfach sind. Zum Beispiel könnte ich ein Array-Objekt erstellen, das beliebige Elemente eines beliebigen Typs enthält, einschließlich sich selbst, und neue Arrays dynamisch erstellen, indem ich eine Nachricht an alle Array-Elemente übergebe und die Rückgabewerte sammle (ähnlich wie bei Map in Lisp). Ein weiterer Grund war die Implementierung der Schlüsselwertbeobachtung, bei der ich die Benutzeroberfläche so einrichten konnte, dass sie sofort auf Änderungen in den Mitgliedern der Backend-Klassen reagiert, anstatt die Daten ständig abzufragen oder die Anzeige unnötig neu zu zeichnen.
Vielleicht interessanter für Sie ist die Tatsache, dass Sie auch alle für eine Klasse definierten Methoden und Mitglieder und nicht weniger in Zeichenfolgenform sichern können.
Nachteile des Systems, die Sie möglicherweise davon abhalten, sich Sorgen zu machen: Das Hinzufügen aller Nachrichten und Schlüsselwerte ist äußerst mühsam. es ist langsamer als ohne Reflexion; Sie werden wachsen, um zu sehen
boost::static_pointer_cast
und zu hassenboost::dynamic_pointer_cast
Ihre gesamte Codebasis mit einer gewalttätigen Leidenschaft . Die Einschränkungen des stark typisierten Systems sind immer noch vorhanden. Sie verstecken sie nur ein wenig, sodass dies nicht so offensichtlich ist. Tippfehler in Ihren Saiten sind auch keine lustige oder leicht zu entdeckende Überraschung.Um so etwas zu implementieren: Verwenden Sie einfach gemeinsame und schwache Zeiger auf eine gemeinsame Basis (meine wurde sehr einfallsreich als "Objekt" bezeichnet) und leiten Sie sie für alle Typen ab, die Sie verwenden möchten. Ich würde empfehlen, Boost.Function zu installieren, anstatt es so zu machen, wie ich es getan habe, was mit etwas benutzerdefiniertem Mist und einer Menge hässlicher Makros geschehen war, um die Funktionszeigeraufrufe zu verpacken. Da alles zugeordnet ist, müssen beim Überprüfen von Objekten nur alle Schlüssel durchlaufen werden. Da meine Klassen im Wesentlichen so nah wie möglich an einer direkten Abzocke von Cocoa mit nur C ++ waren, würde ich vorschlagen, die Cocoa-Dokumentation als Blaupause zu verwenden, wenn Sie so etwas wollen.
quelle
Es gibt eine weitere neue Bibliothek für die Reflexion in C ++, RTTR (Run Time Type Reflection, siehe auch github ).
Die Schnittstelle ähnelt der Reflexion in C # und funktioniert ohne RTTI.
quelle
Die zwei reflexionsartigen Lösungen, die ich aus meiner C ++ - Zeit kenne, sind:
1) Verwenden Sie RTTI, das Ihnen einen Bootstrap zum Erstellen Ihres reflexionsähnlichen Verhaltens bietet, wenn Sie alle Ihre Klassen von einer 'Objekt'-Basisklasse ableiten können. Diese Klasse kann einige Methoden wie GetMethod, GetBaseClass usw. bereitstellen. Für die Funktionsweise dieser Methoden müssen Sie manuell einige Makros hinzufügen, um Ihre Typen zu dekorieren. Hinter den Kulissen werden Metadaten im Typ erstellt, um Antworten auf GetMethods usw. bereitzustellen.
2) Wenn Sie Zugriff auf die Compilerobjekte haben, können Sie auch das DIA SDK verwenden . Wenn ich mich richtig erinnere, können Sie damit pdbs öffnen, die Metadaten für Ihre C ++ - Typen enthalten sollten. Es könnte ausreichen, um das zu tun, was Sie brauchen. Diese Seite zeigt, wie Sie beispielsweise alle Basistypen einer Klasse abrufen können.
Beide Lösungen sind allerdings etwas hässlich! Es gibt nichts Schöneres als ein bisschen C ++, um den Luxus von C # zu schätzen.
Viel Glück.
quelle
BEARBEITEN: Der defekte Link wurde am 7. Februar 2017 aktualisiert.
Ich denke, niemand hat dies erwähnt:
Am CERN verwenden sie ein Vollreflexionssystem für C ++:
CERN Reflex . Es scheint sehr gut zu funktionieren.
quelle
Diese Frage ist jetzt etwas alt (ich weiß nicht, warum ich heute immer wieder alte Fragen stelle), aber ich habe über BOOST_FUSION_ADAPT_STRUCT nachgedacht, das die Reflexion zur Kompilierungszeit einführt.
Es liegt natürlich an Ihnen, dies der Laufzeitreflexion zuzuordnen, und es wird nicht allzu einfach sein, aber es ist in dieser Richtung möglich, während es nicht umgekehrt wäre :)
Ich denke wirklich, dass ein Makro zum Einkapseln des
BOOST_FUSION_ADAPT_STRUCT
einen die notwendigen Methoden generieren könnte, um das Laufzeitverhalten zu erhalten.quelle
Ich denke, Sie könnten den Artikel "Verwenden von Vorlagen zur Reflexion in C ++" von Dominic Filion interessant finden. Es befindet sich in Abschnitt 1.4 von Game Programming Gems 5 . Leider habe ich mein Exemplar nicht dabei, aber suchen Sie danach, weil es meiner Meinung nach erklärt, wonach Sie fragen.
quelle
Ponder ist eine C ++ - Reflexionsbibliothek zur Beantwortung dieser Frage. Ich überlegte mir die Optionen und beschloss, meine eigenen zu machen, da ich keine finden konnte, die alle meine Kriterien erfüllte.
Obwohl es gute Antworten auf diese Frage gibt, möchte ich keine Tonnen von Makros verwenden oder mich auf Boost verlassen. Boost ist eine großartige Bibliothek, aber es gibt viele kleine maßgeschneiderte C ++ 0x-Projekte, die einfacher sind und schnellere Kompilierungszeiten haben. Es hat auch Vorteile, eine Klasse extern dekorieren zu können, z. B. das Umschließen einer C ++ - Bibliothek, die (noch?) C ++ 11 nicht unterstützt. Es ist eine Verzweigung von CAMP unter Verwendung von C ++ 11, die Boost nicht mehr benötigt .
quelle
Bei der Reflexion geht es im Wesentlichen darum, was der Compiler als Footprints im Code hinterlassen hat, den der Laufzeitcode abfragen kann. C ++ ist dafür bekannt, dass Sie nicht für das bezahlen, was Sie nicht verwenden. weil die meisten Menschen nicht verwenden / wollen Reflexion, die C ++ Compiler , die Kosten durch nicht Aufzeichnung vermeidet alles .
C ++ bietet also keine Reflexion und es ist nicht einfach, es selbst als allgemeine Regel zu "simulieren", wie andere Antworten festgestellt haben.
Wenn Sie unter "Andere Techniken" keine Sprache mit Reflexion haben, erhalten Sie ein Tool, mit dem Sie die gewünschten Informationen zur Kompilierungszeit extrahieren können.
Unser DMS Software Reengineering Toolkit ist eine verallgemeinerte Compilertechnologie, die durch explizite Sprachdefinitionen parametrisiert wird. Es hat Sprachdefinitionen für C, C ++, Java, COBOL, PHP, ...
Für C-, C ++ -, Java- und COBOL-Versionen bietet es vollständigen Zugriff auf Analysebäume und Symboltabelleninformationen. Diese Symboltabelleninformationen enthalten die Art von Daten, die Sie wahrscheinlich von "Reflexion" erwarten. Wenn Sie bestimmte Felder oder Methoden auflisten und etwas damit tun möchten, können Sie mit DMS den Code auf beliebige Weise entsprechend den Angaben in den Symboltabellen transformieren.
quelle
Eine weitere Bibliothek finden Sie hier: http://www.garret.ru/cppreflection/docs/reflect.html Es werden zwei Möglichkeiten unterstützt: Typinformationen aus Debug-Informationen abrufen und Programmierer diese Informationen bereitstellen lassen.
Ich habe mich auch für Reflexion für mein Projekt interessiert und diese Bibliothek gefunden. Ich habe sie noch nicht ausprobiert, aber andere Tools von diesem Typen ausprobiert und ich mag, wie sie funktionieren :-)
quelle
Schauen Sie sich Classdesc http://classdesc.sf.net an . Es bietet Reflexion in Form von Klassendeskriptoren, funktioniert mit jedem Standard-C ++ - Compiler (ja, es ist bekannt, dass es sowohl mit Visual Studio als auch mit GCC funktioniert) und erfordert keine Quellcode-Annotation (obwohl einige Pragmas existieren, um schwierige Situationen zu bewältigen ). Es befindet sich seit mehr als einem Jahrzehnt in der Entwicklung und wird in einer Reihe von Projekten im industriellen Maßstab eingesetzt.
quelle
Als ich in C ++ nachdenken wollte, las ich diesen Artikel und verbesserte das, was ich dort sah. Sorry, keine Dose hat. Ich besitze das Ergebnis nicht ... aber Sie können sicher bekommen, was ich hatte und von dort aus gehen.
Ich recherchiere derzeit nach Methoden, um die Definition von reflektierbaren Typen zu vereinfachen, wenn ich Lust dazu habe. Ich bin eigentlich ziemlich weit gekommen, aber ich habe noch einen weiten Weg vor mir. Die Änderungen in C ++ 0x sind in diesem Bereich sehr wahrscheinlich eine große Hilfe.
quelle
Es sieht so aus, als ob C ++ diese Funktion immer noch nicht hat. Und C ++ 11 hat auch die Reflexion verschoben ((
Suchen Sie nach Makros oder erstellen Sie eigene. Qt kann auch bei der Reflexion helfen (wenn es verwendet werden kann).
quelle
Auch wenn Reflection in C ++ nicht sofort unterstützt wird, ist die Implementierung nicht allzu schwierig. Ich bin auf diesen großartigen Artikel gestoßen: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html
Der Artikel erklärt ausführlich, wie Sie ein ziemlich einfaches und rudimentäres Reflexionssystem implementieren können. Zugegeben, es ist nicht die gesundeste Lösung, und es gibt noch Ecken und Kanten, die aussortiert werden müssen, aber für meine Bedürfnisse war es ausreichend.
Fazit: Reflexion kann sich bei richtiger Ausführung auszahlen und ist in c ++ durchaus machbar.
quelle
Ich möchte für die Existenz des automatischen Introspektions- / Reflexions-Toolkits "IDK" werben. Es verwendet einen Meta-Compiler wie den von Qt und fügt Metainformationen direkt in Objektdateien ein. Es soll einfach zu bedienen sein. Keine externen Abhängigkeiten. Sie können sogar std :: string automatisch widerspiegeln und dann in Skripten verwenden. Bitte schauen Sie sich IDK an
quelle
Wenn Sie nach einer relativ einfachen C ++ - Reflexion suchen - ich habe Makros / Definitionen aus verschiedenen Quellen gesammelt und sie kommentiert, wie sie funktionieren. Sie können Header-Dateien hier herunterladen:
https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h
Satz von Definitionen plus Funktionalität darüber hinaus:
https://github.com/tapika/TestCppReflect/blob/master/CppReflect.h https://github.com/tapika/TestCppReflect/blob/master/CppReflect.cpp https://github.com/tapika/TestCppReflect/ blob / master / TypeTraits.h
Die Beispielanwendung befindet sich auch im Git-Repository hier: https://github.com/tapika/TestCppReflect/
Ich werde es hier teilweise mit Erklärung kopieren:
REFLECTABLE
define verwendet Klassennamen + Feldnamen mitoffsetof
-, um zu identifizieren, an welcher Stelle im Speicher sich ein bestimmtes Feld befindet. Ich habe versucht, die .NET-Terminologie so weit wie möglich zu übernehmen, aber C ++ und C # unterscheiden sich, sodass sie nicht 1 zu 1 sind. Das gesamte C ++ - Reflexionsmodell befindet sich inTypeInfo
undFieldInfo
Klassen.Ich habe den pugi xml Parser verwendet, um Demo-Code in xml abzurufen und aus xml wiederherzustellen.
Die vom Demo-Code erzeugte Ausgabe sieht also folgendermaßen aus:
Es ist auch möglich, die Unterstützung von Klassen / Strukturen von Drittanbietern über die TypeTraits-Klasse und die teilweise Vorlagenspezifikation zu aktivieren, um Ihre eigene TypeTraitsT-Klasse zu definieren, ähnlich wie bei CString oder int - siehe Beispielcode in
https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195
Diese Lösung gilt für Windows / Visual Studio. Es ist möglich, es auf andere Betriebssysteme / Compiler zu portieren, hat dies aber noch nicht getan. (Fragen Sie mich, ob Ihnen die Lösung wirklich gefällt, ich kann Ihnen möglicherweise helfen.)
Diese Lösung ist für die einmalige Serialisierung einer Klasse mit mehreren Unterklassen anwendbar.
Wenn Sie jedoch nach einem Mechanismus suchen, um Klassenteile zu serialisieren oder sogar zu steuern, welche Funktionsreflexionsaufrufe erzeugt werden, können Sie sich folgende Lösung ansehen:
https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel
Weitere Informationen finden Sie im YouTube-Video:
C ++ Runtime Type Reflection https://youtu.be/TN8tJijkeFE
Ich versuche etwas tiefer zu erklären, wie die C ++ - Reflexion funktioniert.
Der Beispielcode sieht beispielsweise so aus:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
Aber jeder Schritt hier führt tatsächlich zum Funktionsaufruf Verwenden von C ++ - Eigenschaften mit
__declspec(property(get =, put ... )
.Das Unternehmen erhält vollständige Informationen zu C ++ - Datentypen, C ++ - Eigenschaftsnamen und Klasseninstanzzeigern in Form eines Pfads. Basierend auf diesen Informationen können Sie XML, JSON generieren oder diese sogar über das Internet serialisieren.
Beispiele für solche virtuellen Rückruffunktionen finden Sie hier:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
Siehe Funktionen
ReflectCopy
und virtuelle Funktion::OnAfterSetProperty
.Da das Thema jedoch sehr fortgeschritten ist, empfehle ich, zuerst das Video durchzusehen.
Wenn Sie Verbesserungsvorschläge haben, können Sie mich gerne kontaktieren.
quelle
Die Reflexion in C ++ ist sehr nützlich, wenn Sie dort für jedes Mitglied eine Methode ausführen müssen (z. B. Serialisierung, Hashing, Vergleichen). Ich kam mit einer generischen Lösung mit sehr einfacher Syntax:
Wobei ENUMERATE_MEMBERS ein Makro ist, das später beschrieben wird (UPDATE):
Angenommen, wir haben die Serialisierungsfunktion für int und std :: string wie folgt definiert:
Und wir haben eine generische Funktion in der Nähe des "geheimen Makros";)
Jetzt kannst du schreiben
Wenn Sie also das Makro ENUMERATE_MEMBERS in der Strukturdefinition haben, können Sie Serialisierung, Vergleichen, Hashing und andere Dinge erstellen, ohne den Originaltyp zu berühren. Die einzige Voraussetzung ist die Implementierung der Methode "EnumerateWith" für jeden Typ, der nicht aufzählbar ist, pro Enumerator (wie BinaryWriter). . Normalerweise müssen Sie 10-20 "einfache" Typen implementieren, um jeden Typ in Ihrem Projekt zu unterstützen.
Dieses Makro sollte zur Laufzeit keinen Overhead für die Erstellung / Zerstörung von Strukturen haben, und der Code von T.EnumerateWith () sollte bei Bedarf generiert werden. Dies kann erreicht werden, indem die Template-Inline-Funktion aktiviert wird, also der einzige Overhead in Die ganze Geschichte besteht darin, jeder Struktur ENUMERATE_MEMBERS (m1, m2, m3 ...) hinzuzufügen, während die Implementierung einer bestimmten Methode pro Elementtyp in jeder Lösung ein Muss ist, daher gehe ich nicht davon aus, dass dies Overhead ist.
UPDATE: Es gibt eine sehr einfache Implementierung des Makros ENUMERATE_MEMBERS (es könnte jedoch ein wenig erweitert werden, um die Vererbung von aufzählbaren Strukturen zu unterstützen).
Und für diese 15 Codezeilen benötigen Sie keine Drittanbieter-Bibliothek;)
quelle
Mit BOOST_HANA_DEFINE_STRUCT aus der Boost :: Hana-Bibliothek können Sie coole statische Reflexionsfunktionen für Strukturen erzielen .
Hana ist sehr vielseitig, nicht nur für den Anwendungsfall, den Sie sich vorgestellt haben, sondern auch für viele Metaprogrammierungen von Vorlagen.
quelle
Die Direktzugriffsreflexion Bibliothek ermöglicht eine relativ einfache und intuitive Reflexion. Alle Feld- / Typinformationen sind entweder in Arrays verfügbar oder fühlen sich wie Array-Zugriff an. Es wurde für C ++ 17 geschrieben und funktioniert mit Visual Studios, g ++ und Clang. Die Bibliothek ist nur eine Kopfzeile, dh Sie müssen nur "Reflect.h" in Ihr Projekt kopieren, um sie zu verwenden.
Reflektierte Strukturen oder Klassen benötigen das REFLECT-Makro, in dem Sie den Namen der Klasse angeben, die Sie reflektieren, sowie die Namen der Felder.
Das ist alles, es ist kein zusätzlicher Code erforderlich, um die Reflexion einzurichten. Optional können Sie Oberklassen (in der Klammer des ersten Arguments) und Feldanmerkungen (in der Klammer vor dem Feld, das Sie mit Anmerkungen versehen möchten) angeben, um Oberklassen durchlaufen zu können oder einem Feld zusätzliche Informationen zur Kompilierungszeit hinzuzufügen (z. B. Json: :Ignorieren).
Das Durchlaufen von Feldern kann so einfach sein wie ...
Sie können eine Objektinstanz durchlaufen, um auf Feldwerte (die Sie lesen oder ändern können) und Feldtypinformationen zuzugreifen ...
Eine JSON-Bibliothek basiert auf RandomAccessReflection, die automatisch geeignete JSON-Ausgabedarstellungen zum Lesen oder Schreiben identifiziert und alle reflektierten Felder sowie Arrays und STL-Container rekursiv durchlaufen kann.
Das obige könnte so laufen ...
Siehe auch...
quelle
Wenn Sie einen Zeiger auf eine Funktion wie diese deklarieren:
Sie können dieser Funktion wie folgt einen Speicherplatz zuweisen (erfordert
libdl
unddlopen
)Um ein lokales Symbol mithilfe der Indirektion zu laden, können Sie es
dlopen
für die aufrufende Binärdatei (argv[0]
) verwenden.Die einzige Voraussetzung für diesen (außer
dlopen()
,libdl
unddlfcn.h
), um die Argumente und die Art der Funktion zu kennen.quelle