Siga la décima ley de Greenspun y ya está listo: simplemente implemente una implementación ad hoc, informalmente especificada, llena de errores y lenta de la mitad de Common Lisp. Elija un medio que respalde la implementación de la reflexión. :)
O, aquí está una idea:
Encienda archivos de mapas (y, posiblemente, la generación de montaje) en su construcción. Implemente una aplicación que genere código para crear una biblioteca dinámica. Debería poder obtener toda la información estática (nombres de métodos, parámetros, tipos, etc.) sobre las clases de la fuente o uno de los artefactos de construcción. Al usar el mapa o el ensamblaje, podrá encontrar direcciones de funciones, compensaciones de punteros de funciones virtuales, direcciones de variables globales, compensaciones de variables, información sobre variables asignadas de pila y registro, etc., etc. A partir de esta información construya una biblioteca que contenga las llamadas para obtener toda esta información pasando nombres de tipos, punteros, nombres de funciones, etc.
Ahora, en C++, escriba una biblioteca que contenga funciones y macros que le permitan poner identificaciones únicas que lo harán compilarse en el código para identificar los inicios de funciones, todas las llamadas de reflexión, compensación de EIP tras llamadas de reflexión, etc. Utilice macros de ensamblaje en línea en ubicaciones apropiadas que dejen espacio donde sea necesario con NOPs para poner algunas instrucciones si es necesario, generalmente justo después de CARNÉ DE IDENTIDAD. Además, proporcione funciones de biblioteca de puente que permitan que la funcionalidad de reflexión controle lo que puede alinearse (por ejemplo, obtener la dirección de una función) o tener que realizar llamadas a la biblioteca dinámica incorporada en el paso posterior a la construcción.
Finalmente, escriba un enlazador de reflexión posterior a la compilación. Sugiero "kniltsoPostlink", pero eso depende de usted. En esta etapa de búsqueda de sus identificaciones únicas (¿mencioné para facilitarlo, probablemente debería hacer los ID GUID para que pueda buscarlos en el binario?) Y, donde sea que el ID esté marcando una llamada de reflexión a una función, o una definición de una clase, etc., coloque suficiente información allí (en un formato que pueda determinar fácilmente justo a tiempo al escribir la biblioteca del reflector) y luego en la ID antes de una llamada a la biblioteca del reflector, vuelva a escribir la llamada para que extrae los parámetros que necesita de esos bits de datos, o simplemente coloca los bits de datos allí donde corresponda, no puedo saberlo de antemano, pero a medida que lo escribe, estos pequeños detalles se le aparecerán.
De todos modos, sé que no he dado mucho código, y de hecho tengo la intención de iniciar un proyecto sobre esto en algún momento una vez que tenga suficiente tiempo libre. Quiero decir, cada pequeña parte debería ser muy simple, así que a medida que lo haces de forma incremental, cada pequeña pieza debería quedar clara siempre y cuando sigas las pautas establecidas aquí. Es posible que parte de esto sea incluso más simple de lo que he descrito aquí, porque este fue el peor de los casos. Incluso puede escaparse sin tener que volver a escribir el código en las llamadas reflector; simplemente colocar los datos en los lugares apropiados puede permitir que la biblioteca los extraiga cuando los necesita sin más información.
Estoy muy contento de que haya preguntado; Estoy muy ocupado ahora, pero si tienes una noche gratis, imagino que será un buen comienzo en una primera versión, y estaré encantado de lanzar lo antes posible.
;)
¿No costará esto más que RTTI, entonces, qué gana esto? – Mark
Tough. No puede ordenar el compilador para generar los metadatos que necesita del código fuente. RTTI es extremadamente inadecuado. Tendrá que escribir su propio analizador de lenguaje C++. Eso se ha hecho ... –
@nobugz: Claro, la gente ha escrito sus propios analizadores de C++. Eso está muy lejos de ser trivial. C++ es, muy simplemente, un verdadero dolor para analizar. –