J'aimerais pouvoir introspecter une classe C ++ pour son nom, son contenu (c'est-à-dire les membres et leurs types) etc. Je parle ici de C ++ natif, pas de C ++ géré, qui a une réflexion. Je me rends compte que C ++ fournit des informations limitées en utilisant RTTI. Quelles bibliothèques supplémentaires (ou autres techniques) pourraient fournir ces informations?
c++
reflection
templates
sfinae
pseudo
la source
la source
Réponses:
Ce que vous devez faire, c'est que le préprocesseur génère des données de réflexion sur les champs. Ces données peuvent être stockées sous forme de classes imbriquées.
Tout d'abord, pour faciliter l'écriture dans le préprocesseur, nous utiliserons l'expression typée. Une expression typée n'est qu'une expression qui met le type entre parenthèses. Donc au lieu d'écrire,
int x
vous écrirez(int) x
. Voici quelques macros pratiques pour vous aider avec les expressions typées:Ensuite, nous définissons une
REFLECTABLE
macro pour générer les données sur chaque champ (plus le champ lui-même). Cette macro sera appelée comme ceci:Donc, en utilisant Boost.PP, nous itérons sur chaque argument et générons les données comme ceci:
Cela génère une constante
fields_n
qui est le nombre de champs reflétables dans la classe. Ensuite, il spécialise lefield_data
pour chaque domaine. Il aime aussi lareflector
classe, c'est pour qu'il puisse accéder aux champs même lorsqu'ils sont privés:Maintenant, pour parcourir les champs, nous utilisons le modèle de visiteur. Nous créons une plage MPL de 0 au nombre de champs et accédons aux données de champ à cet index. Il transmet ensuite les données du champ au visiteur fourni par l'utilisateur:
Maintenant, pour le moment de vérité, nous avons mis tout cela ensemble. Voici comment définir une
Person
classe reflétable:Voici une
print_fields
fonction généralisée utilisant les données de réflexion pour parcourir les champs:Un exemple d'utilisation
print_fields
de laPerson
classe réflectable :Quelles sorties:
Et voila, nous venons d'implémenter la réflexion en C ++, en moins de 100 lignes de code.
la source
#define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple
et de#define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__))
changer la définition de TYPEOF (x) en:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Il existe deux types de
reflection
baignade.Ce n'est pas possible avec C ++.
Ce genre de chose est possible avec C ++ en utilisant
template-tricks
. Utilisezboost::type_traits
pour beaucoup de choses (comme vérifier si un type est intégral). Pour vérifier l'existence d'une fonction membre, utilisez Est-il possible d'écrire un modèle pour vérifier l'existence d'une fonction? . Pour vérifier si un certain type imbriqué existe, utilisez SFINAE ordinaire .Si vous cherchez plutôt des moyens d'accomplir 1), comme regarder combien de méthodes possède une classe, ou comme obtenir la représentation sous forme de chaîne d'un identifiant de classe, alors je crains qu'il n'y ait pas de moyen C ++ standard de le faire. Vous devez utiliser soit
C ++ est conçu pour la vitesse. Si vous voulez une inspection de haut niveau, comme C # ou Java, alors je crains de devoir vous dire qu'il n'y a aucun moyen sans effort.
la source
members<T>
qui renvoie une liste de tous les membres de T. Si nous voulions avoir une réflexion à l'exécution (c'est-à-dire RTTI mélangé à la réflexion), le compilateur connaîtrait toujours tous les types de base réfléchis. Il est très probablemembers<T>(T&)
qu'il ne serait jamais instancié pour T = std :: string, donc le RTTI pour std :: string ou ses classes dérivées n'a pas besoin d'être inclus.Et j'adorerais un poney, mais les poneys ne sont pas gratuits. :-p
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI est ce que vous allez obtenir. Une réflexion comme celle à laquelle vous pensez - des métadonnées entièrement descriptives disponibles au moment de l'exécution - n'existe tout simplement pas pour C ++ par défaut.
la source
Les informations existent - mais pas dans le format dont vous avez besoin, et uniquement si vous exportez vos classes. Cela fonctionne sous Windows, je ne connais pas les autres plateformes. Utilisation des spécificateurs de classe de stockage comme dans, par exemple:
Cela oblige le compilateur à construire les données de définition de classe dans la DLL / Exe. Mais ce n'est pas dans un format que vous pouvez facilement utiliser pour la réflexion.
Dans ma société, nous avons construit une bibliothèque qui interprète ces métadonnées et vous permet de refléter une classe sans insérer de macros supplémentaires, etc. dans la classe elle-même. Il permet d'appeler des fonctions comme suit:
Cela permet effectivement:
La fonction Invoke (this_pointer, ...) a des arguments variables. Évidemment, en appelant une fonction de cette manière, vous contournez des choses comme const-safety et ainsi de suite, de sorte que ces aspects sont implémentés en tant que contrôles d'exécution.
Je suis sûr que la syntaxe pourrait être améliorée, et cela ne fonctionne que sur Win32 et Win64 jusqu'à présent. Nous l'avons trouvé très utile pour avoir des interfaces GUI automatiques pour les classes, créer des propriétés en C ++, diffuser vers et à partir de XML et ainsi de suite, et il n'est pas nécessaire de dériver d'une classe de base spécifique. Si la demande est suffisante, nous pourrions peut-être la mettre en forme pour la sortie.
la source
__declspec(dllexport)
et vous pouvez récupérer les informations à partir d'un fichier .map si vous activez la création de telles lors de la construction.La réflexion n'est pas prise en charge par C ++ hors de la boîte. C'est triste car cela rend les tests défensifs pénibles.
Il existe plusieurs approches pour faire de la réflexion:
Le premier lien semble le plus prometteur (utilise des mods pour cliqueter), le second discute un certain nombre de techniques, le troisième est une approche différente utilisant gcc:
http://www.donw.org/rfl/
https://bitbucket.org/dwilliamson/clreflect
https://root.cern.ch/how/how-use-reflex
Il existe maintenant un groupe de travail pour la réflexion C ++. Voir l'actualité du C ++ 14 @ CERN:
Modifier le 13/08/17:
Depuis le message d'origine, il y a eu un certain nombre de progrès potentiels sur la réflexion. Ce qui suit fournit plus de détails et une discussion sur les différentes techniques et statuts:
Cependant, cela ne semble pas prometteur sur une approche de réflexions standardisées en C ++ dans un avenir proche, à moins que la communauté ne s'intéresse beaucoup plus à la réflexion en C ++.
Ce qui suit détaille l'état actuel en fonction des commentaires de la dernière réunion des normes C ++:
Modifier le 13/12/2017
La réflexion semble se diriger vers C ++ 20 ou plus probablement un TSR. Le mouvement est cependant lent.
Modifier 15/09/2018
Un projet de ST a été envoyé aux organismes nationaux pour vote.
Le texte peut être trouvé ici: https://github.com/cplusplus/reflection-ts
Modifier le 11/07/2019
La réflexion TS est une fonctionnalité complète et est disponible pour commentaires et vote au cours de l'été (2019).
L'approche de programmation des méta-modèles doit être remplacée par une approche de code temporel de compilation plus simple (non reflétée dans le TS).
Modifier 10/02/2020
Il y a une demande pour prendre en charge la réflexion TS dans Visual Studio ici:
Conférence sur le TS de l'auteur David Sankel:
http://cppnow.org/history/2019/talks/
https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be
Modifier 17 mars 2020
Des progrès dans la réflexion sont en cours. Un rapport du '2020-02 Prague ISO C ++ Committee Trip Report' peut être trouvé ici:
Des détails sur ce qui est envisagé pour C ++ 23 peuvent être trouvés ici (comprend une courte section sur la réflexion):
Edit 4 juin 2020
Un nouveau cadre a été publié par Jeff Preshing appelé «Plywood» qui contient un mécanisme de réflexion à l'exécution. Plus de détails ici:
Les outils et l'approche semblent être les plus raffinés et les plus faciles à utiliser jusqu'à présent.
la source
Vous devez regarder ce que vous essayez de faire et si RTTI répondra à vos besoins. J'ai implémenté ma propre pseudo-réflexion à des fins très spécifiques. Par exemple, je voulais une fois pouvoir configurer de manière flexible ce qu'une sortie de simulation produirait. Il a fallu ajouter du code passe-partout aux classes qui seraient sorties:
Le premier appel ajoute cet objet au système de filtrage, qui appelle la
BuildMap()
méthode pour déterminer les méthodes disponibles.Ensuite, dans le fichier de configuration, vous pouvez faire quelque chose comme ceci:
Grâce à une magie de modèle impliquant
boost
, cela est traduit en une série d'appels de méthode au moment de l'exécution (lorsque le fichier de configuration est lu), il est donc assez efficace. Je ne recommanderais pas cela sauf si vous en avez vraiment besoin, mais quand vous le faites, vous pouvez faire des trucs vraiment cool.la source
Je recommanderais d'utiliser Qt .
Il existe une licence open source ainsi qu'une licence commerciale.
la source
Qu'essayez-vous de faire avec la réflexion?
Vous pouvez utiliser les traits de type Boost et les bibliothèques typeof comme une forme limitée de réflexion au moment de la compilation. Autrement dit, vous pouvez inspecter et modifier les propriétés de base d'un type transmis à un modèle.
la source
EDIT : CAMP n'est plus maintenu; deux fourches sont disponibles:
CAMP est une bibliothèque sous licence MIT (anciennement LGPL) qui ajoute de la réflexion au langage C ++. Il ne nécessite pas d'étape de prétraitement spécifique dans la compilation, mais la liaison doit être effectuée manuellement.
La bibliothèque Tegesoft actuelle utilise Boost, mais il existe également un fork utilisant C ++ 11 qui ne nécessite plus Boost .
la source
J'ai fait quelque chose comme ce que vous recherchez une fois, et bien qu'il soit possible d'obtenir un certain niveau de réflexion et d'accéder à des fonctionnalités de niveau supérieur, le mal de tête lié à la maintenance n'en vaut peut-être pas la peine. Mon système a été utilisé pour maintenir les classes d'interface utilisateur complètement séparées de la logique métier par le biais d'une délégation semblable au concept d'Objective-C de transmission et de transfert de messages. La façon de le faire est de créer une classe de base capable de mapper des symboles (j'ai utilisé un pool de chaînes mais vous pouvez le faire avec des énumérations si vous préférez la gestion des erreurs de vitesse et de compilation plutôt que la flexibilité totale) pour faire fonctionner des pointeurs (en fait pas des pointeurs de fonction purs, mais quelque chose de similaire à ce que Boost a avec Boost.Function - auquel je n'avais pas accès à l'époque). Vous pouvez faire la même chose pour vos variables membres tant que vous avez une classe de base commune capable de représenter n'importe quelle valeur. L'ensemble du système était une arnaque sans faille du codage et de la délégation des valeurs-clés, avec quelques effets secondaires qui valaient peut-être le temps nécessaire pour que chaque classe utilisant le système associe toutes ses méthodes et ses membres à des appels légaux. : 1) Toute classe pourrait appeler n'importe quelle méthode sur n'importe quelle autre classe sans avoir à inclure des en-têtes ou écrire de fausses classes de base afin que l'interface puisse être prédéfinie pour le compilateur; et 2) Les getters et setters des variables membres étaient faciles à rendre thread-safe car la modification ou l'accès à leurs valeurs se faisait toujours par 2 méthodes dans la classe de base de tous les objets. L'ensemble du système était une arnaque sans faille du codage et de la délégation des valeurs-clés, avec quelques effets secondaires qui valaient peut-être le temps nécessaire pour que chaque classe utilisant le système associe toutes ses méthodes et ses membres à des appels légaux. : 1) Toute classe pourrait appeler n'importe quelle méthode sur n'importe quelle autre classe sans avoir à inclure des en-têtes ou écrire de fausses classes de base afin que l'interface puisse être prédéfinie pour le compilateur; et 2) Les getters et setters des variables membres étaient faciles à rendre thread-safe car la modification ou l'accès à leurs valeurs se faisait toujours par 2 méthodes dans la classe de base de tous les objets. L'ensemble du système était une arnaque sans faille du codage et de la délégation des valeurs-clés, avec quelques effets secondaires qui valaient peut-être le temps nécessaire pour que chaque classe utilisant le système associe toutes ses méthodes et ses membres à des appels légaux. : 1) Toute classe pourrait appeler n'importe quelle méthode sur n'importe quelle autre classe sans avoir à inclure des en-têtes ou écrire de fausses classes de base afin que l'interface puisse être prédéfinie pour le compilateur; et 2) Les getters et setters des variables membres étaient faciles à rendre thread-safe car la modification ou l'accès à leurs valeurs se faisait toujours par 2 méthodes dans la classe de base de tous les objets. 1) N'importe quelle classe pourrait appeler n'importe quelle méthode sur n'importe quelle autre classe sans avoir à inclure des en-têtes ou écrire de fausses classes de base afin que l'interface puisse être prédéfinie pour le compilateur; et 2) Les getters et setters des variables membres étaient faciles à rendre thread-safe car la modification ou l'accès à leurs valeurs se faisait toujours par 2 méthodes dans la classe de base de tous les objets. 1) N'importe quelle classe pourrait appeler n'importe quelle méthode sur n'importe quelle autre classe sans avoir à inclure des en-têtes ou écrire de fausses classes de base afin que l'interface puisse être prédéfinie pour le compilateur; et 2) Les getters et setters des variables membres étaient faciles à rendre thread-safe car la modification ou l'accès à leurs valeurs se faisait toujours par 2 méthodes dans la classe de base de tous les objets.
Cela a également conduit à la possibilité de faire des choses vraiment étranges qui autrement ne sont pas faciles en C ++. Par exemple, je pourrais créer un objet Array qui contenait des éléments arbitraires de tout type, y compris lui-même, et créer de nouveaux tableaux dynamiquement en passant un message à tous les éléments du tableau et en collectant les valeurs de retour (similaire à la carte en Lisp). Un autre a été l'implémentation de l'observation des valeurs-clés, grâce à laquelle j'ai pu configurer l'interface utilisateur pour répondre immédiatement aux changements dans les membres des classes backend au lieu d'interroger constamment les données ou de redessiner inutilement l'affichage.
Peut-être plus intéressant pour vous est le fait que vous pouvez également vider toutes les méthodes et les membres définis pour une classe, et sous forme de chaîne non moins.
Inconvénients du système qui pourraient vous décourager de déranger: l'ajout de tous les messages et valeurs-clés est extrêmement fastidieux; c'est plus lent que sans aucune réflexion; vous allez détester voir
boost::static_pointer_cast
etboost::dynamic_pointer_cast
partout dans votre base de code avec une passion violente; les limites du système fortement typé sont toujours là, vous les cachez juste un peu donc ce n'est pas aussi évident. Les fautes de frappe dans vos cordes ne sont pas non plus une surprise amusante ou facile à découvrir.Quant à la façon d'implémenter quelque chose comme ceci: utilisez simplement des pointeurs partagés et faibles vers une base commune (la mienne était très imaginativement appelée "Object") et dérivez pour tous les types que vous souhaitez utiliser. Je recommanderais d'installer Boost.Function au lieu de le faire comme je l'ai fait, ce qui était avec de la merde personnalisée et une tonne de macros laides pour encapsuler les appels du pointeur de fonction. Étant donné que tout est mappé, l'inspection des objets consiste simplement à parcourir toutes les clés. Étant donné que mes classes étaient essentiellement aussi proches d'une arnaque directe de Cocoa que possible en utilisant uniquement C ++, si vous voulez quelque chose comme ça, je vous suggère d'utiliser la documentation Cocoa comme modèle.
la source
Il existe une autre nouvelle bibliothèque de réflexion en C ++, appelée RTTR (Run Time Type Reflection, voir aussi github ).
L'interface est similaire à la réflexion en C # et elle fonctionne sans RTTI.
la source
Les deux solutions de réflexion que je connais depuis mes jours en C ++ sont:
1) Utilisez RTTI, qui vous fournira un bootstrap pour construire votre comportement de réflexion, si vous êtes en mesure de faire dériver toutes vos classes à partir d'une classe de base «objet». Cette classe pourrait fournir des méthodes telles que GetMethod, GetBaseClass etc. En ce qui concerne le fonctionnement de ces méthodes, vous devrez ajouter manuellement des macros pour décorer vos types, qui dans les coulisses créent des métadonnées dans le type pour fournir des réponses à GetMethods, etc.
2) Une autre option, si vous avez accès aux objets du compilateur, est d'utiliser le SDK DIA . Si je me souviens bien, cela vous permet d'ouvrir des pdbs, qui devraient contenir des métadonnées pour vos types C ++. Il suffira peut-être de faire ce dont vous avez besoin. Cette page montre par exemple comment obtenir tous les types de base d'une classe.
Ces deux solutions sont cependant un peu laides! Il n'y a rien de tel qu'un peu de C ++ pour vous faire apprécier le luxe du C #.
Bonne chance.
la source
EDIT: lien cassé mis à jour au 7 février 2017.
Je pense que personne n'a mentionné cela:
Au CERN, ils utilisent un système de réflexion complet pour C ++:
Réflexe du CERN . Cela semble fonctionner très bien.
la source
Cette question est un peu ancienne maintenant (je ne sais pas pourquoi je continue de répondre aux anciennes questions aujourd'hui) mais je pensais à BOOST_FUSION_ADAPT_STRUCT qui introduit la réflexion à la compilation.
C'est à vous de mapper cela à la réflexion à l'exécution bien sûr, et ce ne sera pas trop facile, mais c'est possible dans cette direction, alors que ce ne serait pas dans le sens inverse :)
Je pense vraiment qu'une macro pour encapsuler
BOOST_FUSION_ADAPT_STRUCT
celle pourrait générer les méthodes nécessaires pour obtenir le comportement d'exécution.la source
Je pense que vous pourriez trouver intéressant l'article "Utilisation de modèles pour la réflexion en C ++" de Dominic Filion. C'est dans la section 1.4 de Game Programming Gems 5 . Malheureusement, je n'ai pas ma copie avec moi, mais cherchez-la parce que je pense qu'elle explique ce que vous demandez.
la source
Ponder est une bibliothèque de réflexion C ++, en réponse à cette question. J'ai considéré les options et j'ai décidé d'en créer une car je n'en trouvais pas qui cocherait toutes mes cases.
Bien qu'il existe d'excellentes réponses à cette question, je ne veux pas utiliser des tonnes de macros, ni compter sur Boost. Boost est une excellente bibliothèque, mais il existe de nombreux petits projets C ++ 0x sur mesure qui sont plus simples et ont des temps de compilation plus rapides. Il y a aussi des avantages à pouvoir décorer une classe en externe, comme encapsuler une bibliothèque C ++ qui ne prend pas (encore?) En charge C ++ 11. C'est un fork de CAMP, utilisant C ++ 11, qui ne nécessite plus Boost .
la source
La réflexion porte essentiellement sur ce que le compilateur a décidé de laisser comme empreintes dans le code que le code d'exécution peut interroger. C ++ est célèbre pour ne pas payer pour ce que vous n'utilisez pas; parce que la plupart des gens n'utilisent pas / ne veulent pas de réflexion, le compilateur C ++ évite le coût en n'enregistrant rien .
Ainsi, C ++ ne fournit pas de réflexion, et il n'est pas facile de le "simuler" vous-même en règle générale comme l'ont noté d'autres réponses.
Sous "autres techniques", si vous n'avez pas de langage avec réflexion, procurez-vous un outil qui peut extraire les informations que vous souhaitez au moment de la compilation.
Notre DMS Software Reengineering Toolkit est une technologie de compilation généralisée paramétrée par des définitions de langage explicites. Il a des définitions de langauge pour C, C ++, Java, COBOL, PHP, ...
Pour les versions C, C ++, Java et COBOL, il fournit un accès complet aux arbres d'analyse et aux informations de la table des symboles. Ces informations de table de symboles incluent le type de données que vous voudrez probablement de la "réflexion". Si votre objectif est d'énumérer un ensemble de champs ou de méthodes et de faire quelque chose avec eux, DMS peut être utilisé pour transformer le code en fonction de ce que vous trouvez dans les tables de symboles de manière arbitraire.
la source
Vous pouvez trouver une autre bibliothèque ici: http://www.garret.ru/cppreflection/docs/reflect.html Il prend en charge 2 façons: obtenir des informations de type à partir des informations de débogage et laisser le programmeur fournir ces informations.
Je me suis également intéressé à la réflexion sur mon projet et j'ai trouvé cette bibliothèque, je ne l'ai pas encore essayée, mais j'ai essayé d'autres outils de ce type et j'aime leur fonctionnement :-)
la source
Consultez Classdesc http://classdesc.sf.net . Il fournit une réflexion sous la forme de "descripteurs" de classe, fonctionne avec n'importe quel compilateur C ++ standard (oui, il est connu pour fonctionner avec Visual Studio ainsi que GCC), et ne nécessite pas d'annotation de code source (bien que certains pragmas existent pour gérer les situations délicates ). Il est en développement depuis plus d'une décennie et utilisé dans un certain nombre de projets à l'échelle industrielle.
la source
Lorsque j'ai voulu réfléchir en C ++, j'ai lu cet article et amélioré ce que j'y ai vu. Désolé, non. Je ne suis pas propriétaire du résultat ... mais vous pouvez certainement obtenir ce que j'avais et partir de là.
Je recherche actuellement, quand j'en ai envie, des méthodes à utiliser inherit_linearly pour rendre la définition des types reflétables beaucoup plus facile. Je suis allé assez loin en fait, mais j'ai encore du chemin à faire. Les changements dans C ++ 0x sont très susceptibles d'être d'une grande aide dans ce domaine.
la source
Il semble que C ++ ne dispose toujours pas de cette fonctionnalité. Et C ++ 11 a également reporté la réflexion ((
Recherchez des macros ou créez les vôtres. Qt peut également aider à la réflexion (si elle peut être utilisée).
la source
même si la réflexion n'est pas prise en charge dès le départ en c ++, elle n'est pas trop difficile à implémenter. J'ai rencontré ce grand article: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html
l'article explique en détail comment mettre en œuvre un système de réflexion assez simple et rudimentaire. accordé sa solution pas la plus saine, et il y a des bords rugueux à régler mais pour mes besoins c'était suffisant.
la ligne de fond - la réflexion peut être payante si elle est effectuée correctement, et elle est complètement réalisable en c ++.
la source
Je voudrais annoncer l'existence de la boîte à outils automatique d'introspection / réflexion "IDK". Il utilise un méta-compilateur comme Qt et ajoute des méta-informations directement dans les fichiers objets. Il serait facile à utiliser. Pas de dépendances externes. Il vous permet même de refléter automatiquement std :: string puis de l'utiliser dans des scripts. Veuillez regarder IDK
la source
Si vous recherchez une réflexion C ++ relativement simple - j'ai collecté à partir de diverses sources macro / définit et commenté leur fonctionnement. Vous pouvez télécharger les fichiers d'en-tête ici:
https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h
ensemble de définitions, plus des fonctionnalités par-dessus:
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
L'exemple d'application réside également dans le référentiel git, ici: https://github.com/tapika/TestCppReflect/
Je vais le copier en partie ici avec explication:
REFLECTABLE
define utilise le nom de la classe + le nom du champ avecoffsetof
- pour identifier à quel endroit de la mémoire se trouve un champ particulier. J'ai essayé de prendre la terminologie .NET pour la mesure du possible, mais C ++ et C # sont différentes, il est donc pas 1 à 1. modèle de réflexion ++ entier C réside dansTypeInfo
etFieldInfo
classes.J'ai utilisé l'analyseur pugi xml pour récupérer le code de démonstration dans xml et le restaurer à partir de xml.
Ainsi, la sortie produite par le code de démonstration ressemble à ceci:
Il est également possible d'activer toute prise en charge de classe / structure tierce via la classe TypeTraits et la spécification partielle de modèle - pour définir votre propre classe TypeTraitsT, de manière similaire à CString ou int - voir l'exemple de code dans
https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195
Cette solution est applicable pour Windows / Visual studio. Il est possible de le porter sur d'autres OS / compilateurs, mais ce n'est pas le cas. (Demandez-moi si vous aimez vraiment la solution, je pourrais peut-être vous aider)
Cette solution est applicable pour la sérialisation à un coup d'une classe avec plusieurs sous-classes.
Cependant, si vous recherchez un mécanisme pour sérialiser des parties de classe ou même pour contrôler les fonctionnalités que les appels de réflexion produisent, vous pouvez jeter un œil à la solution suivante:
https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel
Des informations plus détaillées peuvent être trouvées sur la vidéo youtube:
Réflexion du type d'exécution C ++ https://youtu.be/TN8tJijkeFE
J'essaie d'expliquer un peu plus en détail le fonctionnement de la réflexion c ++.
Un exemple de code ressemblera par exemple à ceci:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
Mais chaque étape aboutit en fait à un appel de fonction à l'aide des propriétés C ++ avec
__declspec(property(get =, put ... )
.qui reçoit des informations complètes sur les types de données C ++, les noms de propriété C ++ et les pointeurs d'instance de classe, sous forme de chemin d'accès, et sur la base de ces informations, vous pouvez générer xml, json ou même sérialiser celui-ci sur Internet.
Des exemples de ces fonctions de rappel virtuel peuvent être trouvés ici:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
Voir les fonctions
ReflectCopy
et la fonction virtuelle::OnAfterSetProperty
.Mais puisque le sujet est vraiment avancé - je recommande de vérifier d'abord la vidéo.
Si vous avez des idées d'amélioration, n'hésitez pas à me contacter.
la source
La bibliothèque Random Access Reflection permet une réflexion assez facile et intuitive - toutes les informations de champ / type sont conçues pour être disponibles dans des tableaux ou pour se sentir comme un accès au tableau. Il est écrit pour C ++ 17 et fonctionne avec Visual Studios, g ++ et Clang. La bibliothèque est uniquement en-tête, ce qui signifie que vous n'avez qu'à copier "Reflect.h" dans votre projet pour l'utiliser.
Les structures ou classes réfléchies ont besoin de la macro REFLECT, où vous fournissez le nom de la classe que vous réfléchissez et les noms des champs.
C'est tout ce qu'il y a, aucun code supplémentaire n'est nécessaire pour configurer la réflexion. Vous pouvez éventuellement fournir des superclasses (dans la parenthèse du premier argument) et des annotations de champ (dans la parenthèse précédant le champ que vous souhaitez annoter) pour pouvoir parcourir les superclasses ou ajouter des informations de compilation supplémentaires à un champ (comme Json: :Ignorer).
La boucle dans les champs peut être aussi simple que ...
Vous pouvez parcourir une instance d'objet pour accéder aux valeurs de champ (que vous pouvez lire ou modifier) et aux informations de type de champ ...
Une bibliothèque JSON est construite au-dessus de RandomAccessReflection qui identifie automatiquement les représentations de sortie JSON appropriées pour la lecture ou l'écriture, et peut parcourir récursivement tous les champs réfléchis, ainsi que les tableaux et les conteneurs STL.
Ce qui précède pourrait être exécuté comme ça ...
Voir également...
la source
La réflexion en C ++ est très utile, dans les cas où vous devez exécuter une méthode pour chaque membre (par exemple: sérialisation, hachage, comparer). Je suis venu avec une solution générique, avec une syntaxe très simple:
Où ENUMERATE_MEMBERS est une macro, qui est décrite plus loin (UPDATE):
Supposons que nous ayons défini une fonction de sérialisation pour int et std :: string comme ceci:
Et nous avons une fonction générique près de la "macro secrète";)
Vous pouvez maintenant écrire
Donc, avec la macro ENUMERATE_MEMBERS dans la définition de la structure, vous pouvez créer la sérialisation, comparer, hacher et d'autres éléments sans toucher au type d'origine, la seule exigence est d'implémenter la méthode "EnumerateWith" pour chaque type, qui n'est pas énumérable, par énumérateur (comme BinaryWriter) . Habituellement, vous devrez implémenter 10 à 20 types "simples" pour prendre en charge n'importe quel type dans votre projet.
Cette macro doit avoir zéro surcharge pour structurer la création / destruction au moment de l'exécution, et le code de T.EnumerateWith () doit être généré à la demande, ce qui peut être réalisé en le faisant fonctionner en tant que modèle en ligne, de sorte que la seule surcharge dans toute l'histoire consiste à ajouter ENUMERATE_MEMBERS (m1, m2, m3 ...) à chaque structure, tout en implémentant une méthode spécifique par type de membre est un must dans toute solution, donc je ne le suppose pas comme une surcharge.
MISE À JOUR: Il existe une implémentation très simple de la macro ENUMERATE_MEMBERS (mais elle pourrait être un peu étendue pour prendre en charge l'héritage de la structure énumérable)
Et vous n'avez besoin d'aucune bibliothèque tierce pour ces 15 lignes de code;)
la source
Vous pouvez obtenir des fonctionnalités de réflexion statique intéressantes pour les structures avec BOOST_HANA_DEFINE_STRUCT à partir de la bibliothèque Boost :: Hana.
Hana est assez polyvalent, non seulement pour le cas d'utilisation que vous avez en tête, mais pour beaucoup de métaprogrammation de modèles.
la source
Si vous déclarez un pointeur sur une fonction comme celle-ci:
Vous pouvez attribuer une place en mémoire à cette fonction comme ceci (nécessite
libdl
etdlopen
)Pour charger un symbole local en utilisant l'indirection, vous pouvez utiliser
dlopen
sur le binaire appelant (argv[0]
).La seule exigence pour cela (autre que
dlopen()
,libdl
etdlfcn.h
) est de connaître les arguments et le type de la fonction.la source