Me gustaría poder introspectar una clase de C ++ para su nombre, contenido (es decir, miembros y sus tipos), etc. Estoy hablando de C ++ nativo aquí, no C ++ administrado, que tiene reflexión. Me doy cuenta de que C ++ proporciona información limitada usando RTTI. ¿Qué bibliotecas adicionales (u otras técnicas) podrían proporcionar esta información?
c++
reflection
templates
sfinae
Mella
fuente
fuente
Respuestas:
Lo que debe hacer es que el preprocesador genere datos de reflexión sobre los campos. Estos datos se pueden almacenar como clases anidadas.
Primero, para que sea más fácil y limpio escribirlo en el preprocesador, usaremos la expresión escrita. Una expresión escrita es solo una expresión que pone el tipo entre paréntesis. Entonces, en lugar de escribir
int x
, escribirás(int) x
. Aquí hay algunas macros útiles para ayudar con las expresiones escritas:A continuación, definimos una
REFLECTABLE
macro para generar los datos sobre cada campo (más el campo en sí). Esta macro se llamará así:Entonces, usando Boost.PP iteramos sobre cada argumento y generamos los datos de esta manera:
Lo que esto hace es generar una constante
fields_n
que es el número de campos reflectantes en la clase. Luego se especializafield_data
para cada campo. También es amiga de lareflector
clase, esto es para que pueda acceder a los campos incluso cuando son privados:Ahora, para recorrer los campos, usamos el patrón de visitante. Creamos un rango MPL de 0 a la cantidad de campos, y accedemos a los datos de campo en ese índice. Luego pasa los datos del campo al visitante proporcionado por el usuario:
Ahora, por el momento de la verdad, lo juntamos todo. Así es como podemos definir una
Person
clase que sea reflectante:Aquí hay una
print_fields
función generalizada que utiliza los datos de reflexión para iterar sobre los campos:Un ejemplo de uso de
print_fields
con laPerson
clase reflectante :Qué salidas:
Y listo, acabamos de implementar la reflexión en C ++, en menos de 100 líneas de código.
fuente
#define DETAIL_TYPEOF_INT2(tuple) DETAIL_TYPEOF_HEAD tuple
y#define DETAIL_TYPEOF_INT(...) DETAIL_TYPEOF_INT2((__VA_ARGS__))
y cambie la definición de TYPEOF (x) a:#define TYPEOF(x) DETAIL_TYPEOF_INT(DETAIL_TYPEOF_PROBE x,)
Hay dos tipos de
reflection
natación alrededor.Esto no es posible con C ++.
Este tipo de cosas es posible con C ++ usando
template-tricks
. Úseloboost::type_traits
para muchas cosas (como verificar si un tipo es integral). Para verificar la existencia de una función miembro, use ¿Es posible escribir una plantilla para verificar la existencia de una función? . Para verificar si existe cierto tipo anidado, use SFINAE simple .Si está buscando formas de lograr 1), como mirar cuántos métodos tiene una clase, o como obtener la representación de cadena de una identificación de clase, entonces me temo que no hay una forma estándar de C ++ de hacer esto. Tienes que usar cualquiera
C ++ está hecho teniendo en cuenta la velocidad. Si desea una inspección de alto nivel, como C # o Java, entonces me temo que debo decirle que no hay forma sin algún esfuerzo.
fuente
members<T>
que devuelve una lista de todos los miembros de T. Si quisiéramos tener una reflexión en tiempo de ejecución (es decir, RTTI mezclado con reflexión), el compilador aún conocería todos los tipos base reflejados. Es muy probablemembers<T>(T&)
que nunca se cree una instancia para T = std :: string, por lo que no es necesario incluir el RTTI para std :: string o sus clases derivadas.Y me encantaría un pony, pero los ponis no son libres. :-pags
http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI es lo que vas a obtener. Una reflexión como la que está pensando: metadatos completamente descriptivos disponibles en tiempo de ejecución, simplemente no existe para C ++ de forma predeterminada.
fuente
La información existe, pero no en el formato que necesita, y solo si exporta sus clases. Esto funciona en Windows, no sé sobre otras plataformas. Usando los especificadores de clase de almacenamiento como en, por ejemplo:
Esto hace que el compilador compile los datos de definición de clase en la DLL / Exe. Pero no está en un formato que pueda usar fácilmente para la reflexión.
En mi empresa, creamos una biblioteca que interpreta estos metadatos y le permite reflejar una clase sin insertar macros adicionales, etc. en la clase misma. Permite que las funciones se llamen de la siguiente manera:
Esto efectivamente hace:
La función Invocar (this_pointer, ...) tiene argumentos variables. Obviamente, al llamar a una función de esta manera, está eludiendo cosas como la seguridad constante, etc., por lo que estos aspectos se implementan como verificaciones de tiempo de ejecución.
Estoy seguro de que la sintaxis podría mejorarse, y hasta ahora solo funciona en Win32 y Win64. Lo hemos encontrado realmente útil para tener interfaces GUI automáticas para las clases, crear propiedades en C ++, transmitir hacia y desde XML, etc., y no es necesario derivar de una clase base específica. Si hay suficiente demanda, tal vez podríamos ponerlo en forma para su lanzamiento.
fuente
__declspec(dllexport)
y puedes recuperar la información del archivo .map si habilitas la creación de este durante la compilación.La reflexión no es compatible con C ++ fuera de la caja. Esto es triste porque hace que las pruebas defensivas sean un dolor.
Hay varios enfoques para hacer la reflexión:
El primer enlace parece el más prometedor (usa mod's para hacer sonar), el segundo discute una serie de técnicas, el tercero es un enfoque diferente usando gcc:
http://www.donw.org/rfl/
https://bitbucket.org/dwilliamson/clreflect
https://root.cern.ch/how/how-use-reflex
Ahora hay un grupo de trabajo para la reflexión en C ++. Vea las noticias para C ++ 14 @ CERN:
Edición 13/08/17:
Desde la publicación original ha habido una serie de posibles avances en la reflexión. Lo siguiente proporciona más detalles y una discusión sobre las diversas técnicas y estado:
Sin embargo, no parece prometedor en un enfoque de reflexiones estandarizado en C ++ en el futuro cercano a menos que haya mucho más interés de la comunidad en apoyar la reflexión en C ++.
A continuación se detalla el estado actual basado en los comentarios de la última reunión de estándares de C ++:
Editar 13/12/2017
La reflexión parece estar avanzando hacia C ++ 20 o más probablemente un TSR. Sin embargo, el movimiento es lento.
Editar 15/09/2018
Se envió un borrador de TS a los organismos nacionales para su votación.
El texto se puede encontrar aquí: https://github.com/cplusplus/reflection-ts
Editar 07/11/2019
La reflexión TS está completa y está disponible para comentarios y votaciones durante el verano (2019).
El enfoque de programación de meta-plantilla debe ser reemplazado por un enfoque de código de tiempo de compilación más simple (no reflejado en el TS).
Editar 10/02/2020
Aquí hay una solicitud para admitir la reflexión TS en Visual Studio:
Charla sobre el TS del autor David Sankel:
http://cppnow.org/history/2019/talks/
https://www.youtube.com/watch?v=VMuML6vLSus&feature=youtu.be
Editar 17 de marzo de 2020
Se avanza en la reflexión. Aquí puede encontrar un informe del 'Informe de viaje del comité de Praga ISO C ++ 2020-02':
Los detalles sobre lo que se está considerando para C ++ 23 se pueden encontrar aquí (incluye una breve sección sobre Reflexión):
Edición 4 de junio de 2020
Jeff Preshing ha lanzado un nuevo marco llamado 'Plywood' que contiene un mecanismo para la reflexión en tiempo de ejecución. Más detalles se pueden encontrar aquí:
Las herramientas y el enfoque parecen ser los más pulidos y fáciles de usar hasta ahora.
fuente
Debe mirar lo que está tratando de hacer y si RTTI satisfará sus requisitos. He implementado mi propia pseudo-reflexión para algunos propósitos muy específicos. Por ejemplo, una vez quise poder configurar de manera flexible lo que generaría una simulación. Se requirió agregar un código repetitivo a las clases que se generarían:
La primera llamada agrega este objeto al sistema de filtrado, que llama al
BuildMap()
método para averiguar qué métodos están disponibles.Luego, en el archivo de configuración, puede hacer algo como esto:
A través de la magia de algunas plantillas
boost
, esto se traduce en una serie de llamadas a métodos en tiempo de ejecución (cuando se lee el archivo de configuración), por lo que es bastante eficiente. No recomendaría hacer esto a menos que realmente lo necesites, pero, cuando lo hagas, puedes hacer algunas cosas realmente geniales.fuente
Yo recomendaría usar Qt .
Hay una licencia de código abierto, así como una licencia comercial.
fuente
¿Qué intentas hacer con la reflexión?
Puede utilizar los rasgos de tipo Boost y las bibliotecas typeof como una forma limitada de reflexión en tiempo de compilación. Es decir, puede inspeccionar y modificar las propiedades básicas de un tipo pasado a una plantilla.
fuente
EDITAR : CAMP ya no se mantiene; Hay dos tenedores disponibles:
CAMP es una biblioteca con licencia MIT (anteriormente LGPL) que agrega reflexión al lenguaje C ++. No requiere un paso de preprocesamiento específico en la compilación, pero el enlace debe hacerse manualmente.
La biblioteca actual de Tegesoft usa Boost, pero también hay una bifurcación que usa C ++ 11 que ya no requiere Boost .
fuente
Hice algo como lo que busca una vez, y aunque es posible obtener cierto nivel de reflexión y acceso a funciones de nivel superior, el dolor de cabeza de mantenimiento podría no valer la pena. Mi sistema se usó para mantener las clases de IU completamente separadas de la lógica de negocios mediante una delegación similar al concepto de paso y reenvío de mensajes de Objective-C. La forma de hacerlo es crear una clase base que sea capaz de mapear símbolos (utilicé un conjunto de cadenas pero podría hacerlo con enumeraciones si prefiere la velocidad y el manejo de errores en tiempo de compilación sobre la flexibilidad total) para que funcionen los punteros (en realidad no punteros de función pura, pero algo similar a lo que Boost tiene con Boost.Function, a la que no tenía acceso en ese momento). Puede hacer lo mismo para sus variables miembro siempre que tenga alguna clase base común capaz de representar cualquier valor. Todo el sistema fue una estafa descarada de codificación y delegación de valores clave, con algunos efectos secundarios que tal vez valieron la gran cantidad de tiempo necesario para que cada clase que usara el sistema combinara todos sus métodos y miembros con llamadas legales : 1) Cualquier clase puede llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pueda estar predefinida para el compilador; y 2) Los captadores y establecedores de las variables miembro eran fáciles de hacer seguros para subprocesos porque cambiar o acceder a sus valores siempre se hacía a través de 2 métodos en la clase base de todos los objetos. Todo el sistema fue una estafa descarada de codificación y delegación de valores clave, con algunos efectos secundarios que tal vez valieron la gran cantidad de tiempo necesario para que cada clase que usara el sistema combinara todos sus métodos y miembros con llamadas legales : 1) Cualquier clase puede llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pueda estar predefinida para el compilador; y 2) Los captadores y establecedores de las variables miembro eran fáciles de hacer seguros para subprocesos porque cambiar o acceder a sus valores siempre se hacía a través de 2 métodos en la clase base de todos los objetos. Todo el sistema fue una estafa descarada de codificación y delegación de valores clave, con algunos efectos secundarios que quizás valieron la gran cantidad de tiempo necesario para que cada clase que usara el sistema combinara todos sus métodos y miembros con llamadas legales : 1) Cualquier clase puede llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pueda estar predefinida para el compilador; y 2) Los captadores y establecedores de las variables miembro eran fáciles de hacer seguros para subprocesos porque cambiar o acceder a sus valores siempre se hacía a través de 2 métodos en la clase base de todos los objetos. 1) Cualquier clase puede llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pueda estar predefinida para el compilador; y 2) Los captadores y establecedores de las variables miembro eran fáciles de hacer seguros para subprocesos porque cambiar o acceder a sus valores siempre se hacía a través de 2 métodos en la clase base de todos los objetos. 1) Cualquier clase puede llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pueda estar predefinida para el compilador; y 2) Los captadores y establecedores de las variables miembro eran fáciles de hacer seguros para subprocesos porque cambiar o acceder a sus valores siempre se hacía a través de 2 métodos en la clase base de todos los objetos.
También condujo a la posibilidad de hacer algunas cosas realmente extrañas que de otra manera no serían fáciles en C ++. Por ejemplo, podría crear un objeto Array que contuviera elementos arbitrarios de cualquier tipo, incluido él mismo, y crear nuevas matrices dinámicamente al pasar un mensaje a todos los elementos de la matriz y recopilar los valores de retorno (similar al mapa en Lisp). Otra fue la implementación de la observación de valores clave, mediante la cual pude configurar la interfaz de usuario para responder de inmediato a los cambios en los miembros de las clases de back-end en lugar de sondear constantemente los datos o volver a dibujar innecesariamente la pantalla.
Quizás sea más interesante para usted el hecho de que también puede volcar todos los métodos y miembros definidos para una clase, y en forma de cadena no menos.
Desventajas del sistema que pueden disuadirlo de molestarse: agregar todos los mensajes y valores clave es extremadamente tedioso; es más lento que sin ningún reflejo; llegarás a odiar ver
boost::static_pointer_cast
yboost::dynamic_pointer_cast
toda tu base de código con una pasión violenta; Las limitaciones del sistema fuertemente tipado todavía están ahí, en realidad solo las estás ocultando un poco, por lo que no es tan obvio. Los errores tipográficos en sus cadenas tampoco son una sorpresa divertida o fácil de descubrir.En cuanto a cómo implementar algo como esto: simplemente use punteros compartidos y débiles en alguna base común (el mío se llamaba muy imaginativamente "Objeto") y obtenga todos los tipos que desea usar. Recomiendo instalar Boost.Function en lugar de hacerlo de la manera que lo hice, que fue con un poco de basura personalizada y un montón de macros feas para envolver las llamadas de puntero de función. Como todo está mapeado, inspeccionar objetos es solo cuestión de iterar a través de todas las claves. Dado que mis clases estaban esencialmente lo más cerca posible de una estafa directa de Cocoa usando solo C ++, si quieres algo así, te sugiero que uses la documentación de Cocoa como modelo.
fuente
Hay otra biblioteca nueva para la reflexión en C ++, llamada RTTR (Run Time Type Reflection, ver también github ).
La interfaz es similar a la reflexión en C # y funciona sin RTTI.
fuente
Las dos soluciones de reflexión que conozco de mis días en C ++ son:
1) Use RTTI, que le proporcionará una rutina de arranque para que pueda construir su comportamiento de reflexión, si puede hacer que todas sus clases se deriven de una clase base de 'objeto'. Esa clase podría proporcionar algunos métodos como GetMethod, GetBaseClass, etc. En cuanto a cómo funcionan esos métodos, deberá agregar manualmente algunas macros para decorar sus tipos, que detrás de escena crean metadatos en el tipo para proporcionar respuestas a GetMethods, etc.
2) Otra opción, si tiene acceso a los objetos del compilador es usar el SDK de DIA . Si no recuerdo mal, esto le permite abrir pdbs, que debería contener metadatos para sus tipos de C ++. Puede ser suficiente para hacer lo que necesita. Esta página muestra cómo puede obtener todos los tipos base de una clase, por ejemplo.
Sin embargo, ambas soluciones son un poco feas. No hay nada como un poco de C ++ para hacerte apreciar los lujos de C #.
Buena suerte.
fuente
EDITAR: enlace roto actualizado a partir del 7 de febrero de 2017.
Creo que nadie mencionó esto:
En el CERN usan un sistema de reflexión completo para C ++:
CERN Reflex . Parece funcionar muy bien.
fuente
Esta pregunta es un poco vieja ahora (no sé por qué sigo respondiendo preguntas viejas hoy) pero estaba pensando en BOOST_FUSION_ADAPT_STRUCT que introduce la reflexión en tiempo de compilación.
Depende de usted asignar esto a la reflexión en tiempo de ejecución, por supuesto, y no será demasiado fácil, pero es posible en esta dirección, mientras que no sería al revés :)
Realmente creo que una macro para encapsularla
BOOST_FUSION_ADAPT_STRUCT
podría generar los métodos necesarios para obtener el comportamiento en tiempo de ejecución.fuente
Creo que le puede interesar el artículo "Uso de plantillas para la reflexión en C ++" de Dominic Filion. Está en la sección 1.4 de Game Programming Gems 5 . Desafortunadamente no tengo mi copia conmigo, pero búsquela porque creo que explica lo que está pidiendo.
fuente
Ponder es una biblioteca de reflexión C ++, en respuesta a esta pregunta. Consideré las opciones y decidí hacer la mía ya que no pude encontrar una que marcara todas mis casillas.
Aunque hay excelentes respuestas a esta pregunta, no quiero usar toneladas de macros, ni confiar en Boost. Boost es una gran biblioteca, pero hay muchos pequeños proyectos C ++ 0x a medida que son más simples y tienen tiempos de compilación más rápidos. También hay ventajas de poder decorar una clase externamente, como envolver una biblioteca de C ++ que no admite (¿todavía?) C ++ 11. Es una bifurcación de CAMP, usando C ++ 11, que ya no requiere Boost .
fuente
La reflexión es esencialmente sobre lo que el compilador decidió dejar como huellas en el código que el código de tiempo de ejecución puede consultar. C ++ es famoso por no pagar por lo que no usa; Debido a que la mayoría de la gente no usa / quiere reflexión, el compilador de C ++ evita el costo al no grabar nada .
Por lo tanto, C ++ no proporciona reflexión, y no es fácil "simularlo" usted mismo como regla general, como han señalado otras respuestas.
En "otras técnicas", si no tiene un lenguaje con reflexión, obtenga una herramienta que pueda extraer la información que desea en el momento de la compilación.
Nuestro kit de herramientas de reingeniería de software DMS es una tecnología de compilación generalizada parametrizada por definiciones de lenguaje explícitas. Tiene definiciones de lenguaje para C, C ++, Java, COBOL, PHP, ...
Para las versiones C, C ++, Java y COBOL, proporciona acceso completo a los árboles de análisis e información de la tabla de símbolos. Esa información de la tabla de símbolos incluye el tipo de datos que es probable que desee obtener de "reflexión". Si su objetivo es enumerar algún conjunto de campos o métodos y hacer algo con ellos, DMS se puede utilizar para transformar el código de acuerdo con lo que encuentre en las tablas de símbolos de manera arbitraria.
fuente
Puede encontrar otra biblioteca aquí: http://www.garret.ru/cppreflection/docs/reflect.html Admite 2 formas: obtener información de tipo de la información de depuración y dejar que el programador proporcione esta información.
También me interesó la reflexión para mi proyecto y encontré esta biblioteca, aún no la he probado, pero he probado otras herramientas de este tipo y me gusta cómo funcionan :-)
fuente
Echa un vistazo a Classdesc http://classdesc.sf.net . Proporciona reflexión en forma de "descriptores" de clase, funciona con cualquier compilador estándar de C ++ (sí, se sabe que funciona con Visual Studio y GCC), y no requiere anotaciones de código fuente (aunque existen algunos pragmas para manejar situaciones difíciles) ) Ha estado en desarrollo durante más de una década y se ha utilizado en varios proyectos a escala industrial.
fuente
Cuando quise reflexionar en C ++, leí este artículo y mejoré lo que vi allí. Lo sentimos, no se puede. No soy dueño del resultado ... pero ciertamente puedes obtener lo que tenía e ir desde allí.
Actualmente estoy investigando, cuando me da la gana, métodos para usar herencia_linealmente para hacer que la definición de tipos reflectantes sea mucho más fácil. Llegué bastante lejos en realidad, pero todavía tengo mucho camino por recorrer. Es muy probable que los cambios en C ++ 0x sean de gran ayuda en esta área.
fuente
Parece que C ++ todavía no tiene esta característica. Y C ++ 11 pospuso la reflexión también ((
Buscar algunas macros o hacerlas propias. Qt también puede ayudar con la reflexión (si se puede usar).
fuente
a pesar de que la reflexión no se admite de forma inmediata en c ++, no es demasiado difícil de implementar. Me he encontrado con este gran artículo: http://replicaisland.blogspot.co.il/2010/11/building-reflective-object-system-in-c.html
El artículo explica con gran detalle cómo puede implementar un sistema de reflexión bastante simple y rudimentario. Sin embargo, no es la solución más saludable, y quedan bordes ásperos por resolver, pero para mis necesidades fue suficiente.
la conclusión: la reflexión puede dar sus frutos si se hace correctamente, y es completamente factible en c ++.
fuente
Me gustaría anunciar la existencia del kit de herramientas de introspección / reflexión automática "IDK". Utiliza un metacompilador como Qt's y agrega metainformación directamente a los archivos de objetos. Se afirma que es fácil de usar. Sin dependencias externas. Incluso le permite reflejar automáticamente std :: string y luego usarlo en scripts. Por favor mira IDK
fuente
Si está buscando una reflexión C ++ relativamente simple, he recopilado de varias fuentes macro / define, y les comenté cómo funcionan. Puede descargar archivos de encabezado desde aquí:
https://github.com/tapika/TestCppReflect/blob/master/MacroHelpers.h
conjunto de definiciones, además de funcionalidad además:
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
La aplicación de muestra también se encuentra en el repositorio de git, aquí: https://github.com/tapika/TestCppReflect/
En parte lo copiaré aquí con una explicación:
REFLECTABLE
define usa el nombre de clase + nombre de campo conoffsetof
- para identificar en qué lugar de la memoria se encuentra el campo particular. He intentado recoger la terminología de .NET en la medida de lo posible, pero C ++ y C # son diferentes, por lo que no es de 1 a 1. Todo el modelo de reflexión de C ++ reside enTypeInfo
yFieldInfo
clases.He usado pugi xml parser para recuperar el código de demostración en xml y restaurarlo desde xml.
Entonces la salida producida por el código de demostración se ve así:
También es posible habilitar cualquier soporte de clase / estructura de terceros a través de la clase TypeTraits y la especificación de plantilla parcial: para definir su propia clase TypeTraitsT, de manera similar a CString o int; consulte el código de ejemplo en
https://github.com/tapika/TestCppReflect/blob/master/TypeTraits.h#L195
Esta solución es aplicable para Windows / Visual Studio. Es posible portarlo a otros SO / compiladores, pero no lo he hecho. (Pregúntame si realmente te gusta la solución, podría ayudarte)
Esta solución es aplicable para la serialización de una sola vez de una clase con múltiples subclases.
Sin embargo, si está buscando un mecanismo para serializar partes de clase o incluso para controlar qué funcionalidad producen las llamadas de reflexión, puede echar un vistazo a la siguiente solución:
https://github.com/tapika/cppscriptcore/tree/master/SolutionProjectModel
Se puede encontrar información más detallada en el video de YouTube:
Reflexión de tipo de tiempo de ejecución de C ++ https://youtu.be/TN8tJijkeFE
Estoy tratando de explicar un poco más sobre cómo funcionará la reflexión en C ++.
El código de muestra se verá así, por ejemplo, así:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/testCppApp.cpp
Pero cada paso aquí en realidad da como resultado una llamada a la función Usar propiedades C ++ con
__declspec(property(get =, put ... )
.que recibe información completa sobre los tipos de datos de C ++, los nombres de propiedad de C ++ y los punteros de instancia de clase, en forma de ruta, y en función de esa información, puede generar xml, json o incluso serializarlo a través de Internet.
Aquí se pueden encontrar ejemplos de tales funciones de devolución de llamada virtual:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/VCConfiguration.cpp
Ver funciones
ReflectCopy
y función virtual::OnAfterSetProperty
.Pero como el tema es realmente avanzado, recomiendo revisar primero el video.
Si tiene ideas para mejorar, no dude en ponerse en contacto conmigo.
fuente
La biblioteca de Reflexión de acceso aleatorio permite una reflexión bastante fácil e intuitiva: toda la información de campo / tipo está diseñada para estar disponible en matrices o para sentirse como un acceso de matriz. Está escrito para C ++ 17 y funciona con Visual Studios, g ++ y Clang. La biblioteca es solo un encabezado, lo que significa que solo necesita copiar "Reflect.h" en su proyecto para usarlo.
Las estructuras o clases reflejadas necesitan la macro REFLECT, donde se proporciona el nombre de la clase que está reflejando y los nombres de los campos.
Eso es todo lo que hay, no se necesita código adicional para configurar la reflexión. Opcionalmente, puede proporcionar superclases (en paréntesis del primer argumento) y anotaciones de campo (en el paréntesis que precede al campo que desea anotar) para poder atravesar superclases o agregar información adicional en tiempo de compilación a un campo (como Json: :Ignorar).
Recorrer los campos puede ser tan simple como ...
Puede recorrer una instancia de objeto para acceder a los valores de campo (que puede leer o modificar) y la información del tipo de campo ...
Una biblioteca JSON está construida sobre RandomAccessReflection que identifica automáticamente las representaciones de salida JSON apropiadas para leer o escribir, y puede atravesar recursivamente cualquier campo reflejado, así como matrices y contenedores STL.
Lo anterior podría ejecutarse así ...
Ver también...
fuente
La reflexión en C ++ es muy útil, en caso de que necesite ejecutar algún método para cada miembro (por ejemplo: serialización, hashing, comparación). Vine con una solución genérica, con una sintaxis muy simple:
Donde ENUMERATE_MEMBERS es una macro, que se describe más adelante (ACTUALIZACIÓN):
Supongamos que hemos definido la función de serialización para int y std :: string de esta manera:
Y tenemos una función genérica cerca de la "macro secreta";)
Ahora puedes escribir
Entonces, al tener la macro ENUMERATE_MEMBERS en la definición de estructura, puede construir serialización, comparación, hash y otras cosas sin tocar el tipo original, el único requisito es implementar el método "EnumerateWith" para cada tipo, que no es enumerable, por enumerador (como BinaryWriter) . Por lo general, tendrá que implementar 10-20 tipos "simples" para admitir cualquier tipo en su proyecto.
Esta macro debe tener una sobrecarga cero para estructurar la creación / destrucción en tiempo de ejecución, y el código de T.EnumerateWith () debe generarse a pedido, lo que se puede lograr haciendo que sea una función de plantilla en línea, por lo que la única sobrecarga en toda la historia es agregar ENUMERATE_MEMBERS (m1, m2, m3 ...) a cada estructura, mientras que la implementación de un método específico por tipo de miembro es imprescindible en cualquier solución, por lo que no lo asumo como gastos generales.
ACTUALIZACIÓN: hay una implementación muy simple de la macro ENUMERATE_MEMBERS (sin embargo, podría extenderse un poco para admitir la herencia de la estructura enumerable)
Y no necesita ninguna biblioteca de terceros para estas 15 líneas de código;)
fuente
Puede lograr características de reflexión estática interesantes para estructuras con BOOST_HANA_DEFINE_STRUCT de la biblioteca Boost :: Hana.
Hana es bastante versátil, no solo para el caso de uso que tiene en mente, sino también para una gran cantidad de metaprogramaciones de plantillas.
fuente
Si declara un puntero a una función como esta:
Puede asignar un lugar en la memoria a esa función de esta manera (requiere
libdl
ydlopen
)Para cargar un símbolo local usando indirección, puede usarlo
dlopen
en el binario que llama (argv[0]
).El único requisito para esto (que no sea
dlopen()
,libdl
ydlfcn.h
) es conocer los argumentos y el tipo de la función.fuente