¿Cómo puedo agregar reflexión a una aplicación C++?


Me gustaría poder hacer introspección de una clase de C++ por 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 cierta información limitada usando RTTI. ¿Qué bibliotecas adicionales (u otras técnicas) podrían suministrar esta información?

Author: Lazer, 2008-09-03

30 answers

Lo que necesita hacer es que el preprocesador genere datos de reflexión sobre los campos. Estos datos se pueden almacenar como clases anidadas.

En primer lugar, para que sea más fácil y más limpio escribirlo en el preprocesador usaremos expresión tipada. Una expresión escrita es solo una expresión que pone el tipo entre paréntesis. Así que en lugar de escribir int x escribirás (int) x. Aquí hay algunas macros útiles para ayudar con las expresiones escritas:

#define REM(...) __VA_ARGS__
#define EAT(...)

// Retrieve the type
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
// Strip off the type
#define STRIP(x) EAT x
// Show the type without parenthesis
#define PAIR(x) REM x

A continuación, definimos una macro REFLECTABLE para genere los datos sobre cada campo (más el propio campo). Esta macro se llamará así:

REFLECTABLE
(
    (const char *) name,
    (int) age
)

Así que usando Boost.PP iteramos sobre cada argumento y generamos los datos de esta manera:

// A helper metafunction for adding const to a type
template<class M, class T>
struct make_const
{
    typedef T type;
};

template<class M, class T>
struct make_const<const M, T>
{
    typedef typename boost::add_const<T>::type type;
};


#define REFLECTABLE(...) \
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__); \
friend struct reflector; \
template<int N, class Self> \
struct field_data {}; \
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))

#define REFLECT_EACH(r, data, i, x) \
PAIR(x); \
template<class Self> \
struct field_data<i, Self> \
{ \
    Self & self; \
    field_data(Self & self) : self(self) {} \
    \
    typename make_const<Self, TYPEOF(x)>::type & get() \
    { \
        return self.STRIP(x); \
    }\
    typename boost::add_const<TYPEOF(x)>::type & get() const \
    { \
        return self.STRIP(x); \
    }\
    const char * name() const \
    {\
        return BOOST_PP_STRINGIZE(STRIP(x)); \
    } \
}; \

Lo que esto hace es generar una constante fields_n que es el número de campos reflectables en la clase. Luego se especializa el field_data para cada campo. También es amigo de la clase reflector, esto es para que pueda acceder a los campos incluso cuando son privados:

struct reflector
{
    //Get field_data at index N
    template<int N, class T>
    static typename T::template field_data<N, T> get_field_data(T& x)
    {
        return typename T::template field_data<N, T>(x);
    }

    // Get the number of fields
    template<class T>
    struct fields
    {
        static const int n = T::fields_n;
    };
};

Ahora a iterar sobre los campos que utilizamos el patrón de visitante. Creamos un rango MPL desde 0 hasta el número de campos, y accedemos a los datos de campo en ese índice. Luego pasa los datos del campo al visitante proporcionado por el usuario:

struct field_visitor
{
    template<class C, class Visitor, class I>
    void operator()(C& c, Visitor v, I)
    {
        v(reflector::get_field_data<I::value>(c));
    }
};


template<class C, class Visitor>
void visit_each(C & c, Visitor v)
{
    typedef boost::mpl::range_c<int,0,reflector::fields<C>::n> range;
    boost::mpl::for_each<range>(boost::bind<void>(field_visitor(), boost::ref(c), v, _1));
}

Ahora, para el momento de la verdad, lo juntamos todo. Así es como podemos definir una clase Person que es reflectable:

struct Person
{
    Person(const char *name, int age)
        :
        name(name),
        age(age)
    {
    }
private:
    REFLECTABLE
    (
        (const char *) name,
        (int) age
    )
};

Aquí hay una función generalizada print_fields que usa los datos de reflexión para iterar sobre los campos:

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

Un ejemplo de uso el print_fields con la clase reflectable Person:

int main()
{
    Person p("Tom", 82);
    print_fields(p);
    return 0;
}

Que produce:

name=Tom
age=82

Y listo, acabamos de implementar la reflexión en C++, en menos de 100 líneas de código.

 203
Author: Paul Fultz II,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-20 16:45:45

Hay dos tipos de reflection nadando alrededor.

  1. Inspección iterando sobre los miembros de un tipo, enumerando sus métodos y así sucesivamente.

    Esto no es posible con C++.
  2. Inspección comprobando si un tipo de clase (clase, estructura, unión) tiene un método o tipo anidado, se deriva de otro tipo particular.

    Este tipo de cosas es posible con C++ usando template-tricks. Uso boost::type_traits para muchas cosas (como comprobar si un tipo es integral). Para comprobando la existencia de una función miembro, use ¿Es posible escribir una plantilla para comprobar la existencia de una función? . Para comprobar si existe un cierto tipo anidado, utilice plain SFINAE.

Si está buscando maneras de lograr 1), como ver cuántos métodos tiene una clase, o como obtener la representación de cadena de un id de clase, entonces me temo que no hay una forma estándar de C++ de hacer esto. Usted tiene que utilizar cualquiera

  • A Compilador Meta como el Compilador de Objetos Meta Qt que traduce su código añadiendo información meta adicional.
  • Un Framework constisting de macros que le permiten agregar la meta-información requerida. Tendría que decirle al framework todos los métodos, los nombres de las clases, las clases base y todo lo que necesita.

C++ está hecho con la velocidad en mente. Si desea una inspección de alto nivel, como la que tiene C# o Java, entonces me temo que tengo que decirle que no hay manera sin un poco de esfuerzo.

 96
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:45

Y me encantaría un pony, pero los ponis no son gratis. :- p

Http://en.wikibooks.org/wiki/C%2B%2B_Programming/RTTI es lo que vas a obtener. La reflexión en la que estás pensando metadata metadatos completamente descriptivos disponibles en tiempo de ejecución just simplemente no existe para C++ de forma predeterminada.

 55
Author: Brad Wilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-03 11:04:56

La información existe, pero no en el formato que necesita, y solo si exporta sus clases. Esto funciona en Windows, no conozco otras plataformas. Usando los especificadores de clase de almacenamiento como en, por ejemplo:

class __declspec(export) MyClass
{
public:
    void Foo(float x);
}

Esto hace que el compilador construya los datos de definición de clase en el DLL/Exe. Pero no está en un formato que puedas usar fácilmente para la reflexión.

En mi empresa construimos una biblioteca que interpreta estos metadatos, y le permite reflejar una clase sin insertar macros adicionales, etc. en la clase misma. Permite llamar a las funciones de la siguiente manera:

MyClass *instance_ptr=new MyClass;
GetClass("MyClass")->GetFunction("Foo")->Invoke(instance_ptr,1.331);

Esto efectivamente hace:

instance_ptr->Foo(1.331);

La invocación (this_pointer,...) la función tiene argumentos variables. Obviamente, al llamar a una función de esta manera, está eludiendo cosas como const-safety, etc., por lo que estos aspectos se implementan como comprobaciones de tiempo de ejecución.

Estoy seguro de que la sintaxis podría mejorarse, y solo funciona en Win32 y Win64 hasta ahora. Lo hemos encontrado muy útil para tener interfaces GUI automáticas para las clases, crear propiedades en C++, transmitir hacia y desde XML, etc., y no hay necesidad de derivar de una clase base específica. Si hay suficiente demanda tal vez podríamos ponerlo en forma para su liberación.

 36
Author: Roderick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-11 23:06:26

RTTI no existe para C++.

Esto es simplemente incorrecto. En realidad, el mismo término "RTTI" fue acuñado por el estándar C++. Por otro lado, RTTI no va muy lejos en la implementación de la reflexión.

 35
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-03 13:18:29

Usted necesita mirar lo que usted está intentando 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 ser capaz de configurar de manera flexible lo que una simulación produciría. Se requería agregar algún código repetitivo a las clases que se obtendrían:

namespace {
  static bool b2 = Filter::Filterable<const MyObj>::Register("MyObject");
} 

bool MyObj::BuildMap()
{
  Filterable<const OutputDisease>::AddAccess("time", &MyObj::time);
  Filterable<const OutputDisease>::AddAccess("person", &MyObj::id);
  return true;
}

La primera llamada agrega este objeto al sistema de filtrado, que llama al método BuildMap() para averiguar qué métodos están disponibles.

Luego, en el archivo de configuración, puedes hacer algo como esto:

FILTER-OUTPUT-OBJECT   MyObject
FILTER-OUTPUT-FILENAME file.txt
FILTER-CLAUSE-1        person == 1773
FILTER-CLAUSE-2        time > 2000

A través de alguna magia de plantilla que involucra 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 cosas realmente geniales.

 14
Author: KeithB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-23 16:20:51

¿Qué intentas hacer con la reflexión?
Puede usar las bibliotecas Boost type traits y 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.

 13
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-03 11:33:05

Recomendaría usar Qt.

Hay una licencia de código abierto, así como una licencia comercial.

 13
Author: Jérôme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-03 13:06:38

EDITAR: CAMP ya no se mantiene; hay dos tenedores disponibles:

  • Uno también se llama CAMP también, y se basa en la misma API.
  • Ponder es una reescritura parcial, y se preferirá ya que no requiere Boost ; está usando C++11.

CAMP es una biblioteca con licencia MIT (anteriormente LGPL) que añade reflexión al lenguaje C++. No requiere un paso de preprocesamiento específico en la compilación, pero la encuadernación debe hacerse manualmente.

La biblioteca Tegesoft actual usa Boost, pero también hay una bifurcación usando C++11 que ya no requiere Boost.

 11
Author: philant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-10 12:50:53

Hice algo como lo que buscas una vez, y si bien es posible obtener algún nivel de reflexión y acceso a características de nivel superior, el dolor de cabeza de mantenimiento podría no valer la pena. Mi sistema se utilizó para mantener las clases de interfaz de usuario completamente separadas de la lógica de negocio a través de la delegación similar al concepto de Objective-C de pasar y reenviar mensajes. La forma de hacerlo es crear una clase base que sea capaz de asignar símbolos (usé un grupo 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) a los punteros de función (en realidad no son punteros de función puros, sino algo similar a lo que Boost tiene con Boost.Función Function a la que no tenía acceso en ese momento). Puedes hacer lo mismo para tus variables miembro siempre y cuando tengas alguna clase base común capaz de representar cualquier valor. Todo el sistema fue una estafa descarada de Codificación y Delegación de Valor Clave, con algunos efectos secundarios que quizás fueron vale la pena la gran cantidad de tiempo necesario para obtener cada clase que utiliza el sistema para hacer coincidir todos sus métodos y miembros con llamadas legales: 1) Cualquier clase podía llamar a cualquier método en cualquier otra clase sin tener que incluir encabezados o escribir clases base falsas para que la interfaz pudiera ser predefinida para el compilador; y 2) Los getters y setters de las variables miembro eran fáciles de hacer seguro de 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 llevó 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 de matriz que contuviera elementos arbitrarios de cualquier tipo, incluido él mismo, y crear nuevas matrices dinámicamente pasando un mensaje a todos los elementos de la matriz y recopilando los valores devueltos (similar a map in Lisp). Otra fue la implementación de key-value observing, mediante la cual pude configurar la interfaz de usuario para responder inmediatamente a los cambios en el miembros de clases backend en lugar de sondear constantemente los datos o redibujar innecesariamente la pantalla.

Tal vez más interesante para usted es 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 podrían desalentarte de molestarte: agregar todos los mensajes y valores clave es extremadamente tedioso; es más lento que sin ninguna reflexión; crecerás a odiar ver boost::static_pointer_cast y boost::dynamic_pointer_cast por todas partes código base con una pasión violenta; las limitaciones del sistema fuertemente escrito todavía están ahí, realmente solo las estás escondiendo un poco para que no sea 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 para alguna base común (la mía se llamó muy imaginativamente "Objeto") y derive para todos los tipos que desea usar. Recomiendo instalar Boost.Función en lugar de hacerlo de la manera Lo hice, que fue con alguna basura personalizada y un montón de macros feas para envolver las llamadas de puntero de función. Dado que todo está mapeado, inspeccionar objetos es solo una cuestión de iterar a través de todas las claves. Dado que mis clases eran esencialmente lo más cerca posible de una estafa directa de Cocoa usando solo C++, si quieres algo así, entonces sugeriría usar la documentación de Cocoa como un plano.

 10
Author: Michel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-27 21:41:28

Las dos soluciones similares a la reflexión que conozco de mis días en C++ son:

1) Use RTTI, que le proporcionará un bootstrap para construir su comportamiento similar a la reflexión, si es capaz de obtener todas sus clases para derivar de una clase base 'object'. 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 entre bastidores crean metadatos en el tipo para proporcionar respuestas Obtener métodos, etc.

2) Otra opción, si tiene acceso a los objetos del compilador, es usar el SDK DIA. Si no recuerdo mal, esto le permite abrir pdbs, que deben contener metadatos para sus tipos de C++. Podría ser suficiente para hacer lo que necesitas. Esta página muestra cómo puede obtener todos los tipos base de una clase, por ejemplo.

Ambas soluciones son un poco feas sin embargo! No hay nada como un poco de C++ para que aprecies los lujos de C#.

Bueno Suerte.

 9
Author: user4385,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-03 12:13:09

Hay otra nueva biblioteca para la reflexión en C++, llamada RTTR (Reflexión de tipo de tiempo de ejecución, véase también github).

La interfaz es similar a la reflexión en C# y funciona sin RTTI.

 7
Author: Zack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-15 10:22:51

EDITAR: Enlace roto actualizado a partir del 7 de febrero de 2017.

Creo que nadie mencionó esto:

En el CERN utilizan un sistema de reflexión completa para C++:

CERN Reflex . Parece funcionar muy bien.

 7
Author: Germán Diago,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-07 04:48:08

Esta pregunta es un poco antigua ahora (no sé por qué sigo golpeando preguntas antiguas 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 encapsular el BOOST_FUSION_ADAPT_STRUCT uno podría generar los métodos necesarios para obtener el tiempo de ejecución comportamiento.

 6
Author: Matthieu M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-12 17:05:53

Creo que puede encontrar interesante 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úscala porque creo que explica lo que estás pidiendo.

 5
Author: Luis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-03 15:15:45

La reflexión no es compatible con C++ de forma predeterminada. Esto es triste porque hace que las pruebas defensivas sean un dolor.

Hay varios enfoques para hacer la reflexión:

  1. utilice la información de depuración (no portable).
  2. Espolvoree su código con macro / plantillas o algún otro enfoque de fuente (se ve feo)
  3. Modifique un compilador como clang/gcc para producir una base de datos.
  4. Use el enfoque moc de Qt
  5. Aumentar Reflejar
  6. Preciso y Plano Reflexión

El primer enlace parece el más prometedor( usa mods para clang), el segundo discute una serie de técnicas, el tercero es un enfoque diferente usando gcc:

  1. Http://www.donw.org/rfl/

  2. Https://bitbucket.org/dwilliamson/clreflect

  3. Https://root.cern.ch/how/how-use-reflex

Ahora hay un grupo de trabajo para la reflexión en C++. Ver las noticias de C++14 @ CERN:

Editar 13/08/17: Desde el post original ha habido una serie de avances potenciales en la reflexión. Lo siguiente proporciona más detalles y una discusión sobre las diversas técnicas y el estado:

  1. Reflexión estática en pocas palabras
  2. Reflexión estática
  3. Un diseño para la reflexión estática

Sin Embargo no se ve prometedor en un enfoque estandarizado de reflexiones en C++ en un futuro próximo 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 los estándares de C++:

Editar 13/12/2017

La reflexión parece estar moviéndose hacia C++ 20 o más probablemente un TSR. El movimiento es sin embargo lento.

Editar 15/09/2018

Se ha enviado un proyecto de TS a los órganos nacionales para su votación.

El texto se puede encontrar aquí: https://github.com/cplusplus/reflection-ts

 5
Author: Damian Dixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-15 12:15:05

Ponder es una biblioteca de reflexión de C++, en respuesta a esta pregunta. Consideré las opciones y decidí hacer las mías ya que no pude encontrar una que cumpliera todas mis casillas.

Aunque hay grandes respuestas a esta pregunta, no quiero usar toneladas de macros, o confiar en Boost. Boost es una gran biblioteca, pero hay muchos pequeños proyectos C++0x personalizados 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 lo hace (¿todavía?) soporte C++11. Es la bifurcación de CAMP, usando C++11, que ya no requiere Boost.

 4
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-17 09:05:48

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 se 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 tiempo de compilación.

Nuestro DMS Software Reengineering Toolkit es una tecnología de compilador generalizada parametrizada por definiciones de idioma explícitas. Tiene definiciones de idioma para C, C++, Java, COBOL, PHP,...

Para las versiones de C, C++, Java y COBOL, proporciona acceso completo a los árboles de análisis y a la 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 de "reflexión". Si su objetivo es enumerar algún conjunto de campos o métodos y hacer algo con ellos, DMS se puede usar para transformar el código de acuerdo con lo que encuentre en las tablas de símbolos de manera arbitraria.

 4
Author: Ira Baxter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-08 00:00:18

Puedes encontrar otra biblioteca aquí: http://www.garret.ru/cppreflection/docs/reflect.html Admite 2 formas: obtener información de tipo de 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 probé otras herramientas de este tipo y me gusta cómo funcionan: -)

 3
Author: alariq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-28 08:45:18

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 así como con GCC), y no requiere anotación 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 utiliza en una serie de proyectos a escala industrial.

 3
Author: Russell Standish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-06 07:41:51

Cuando quise reflexionar en C++ leí este artículo y mejoré lo que vi allí. Lo siento, no puede. No soy el dueño del resultado...pero puedes conseguir lo que tenía y partir de ahí.

Actualmente estoy investigando, cuando me apetece, métodos para usar inherit_linearly para hacer la definición de tipos reflectables mucho más fácil. He llegado bastante lejos en ella en realidad, pero todavía tengo un camino por recorrer. Es muy probable que los cambios en C++0x sean de mucha ayuda en esto zona.

 2
Author: Crazy Eddie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-14 04:12:23

Parece Que C++ todavía no tiene esta característica. Y C++11 reflexión pospuesta también ((

Buscar algunas macros o hacer propias. Qt también puede ayudar con la reflexión (si se puede utilizar).

 2
Author: Bohdan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-24 08:23:11

Intenta mirar este proyecto http://www.garret.ru/cppreflection/docs/reflect.html se añaden reflexiones a C++. Agregó metadatos a las clases que luego puede usar.

 2
Author: Damian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-17 10:03:19

A pesar de que la reflexión no es compatible fuera de la caja en c++, no es demasiado difícil de implementar. He encontrado 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 se puede implementar un sistema de reflexión bastante simple y rudimentario. concedido su no la solución más sana, y hay bordes ásperos dejados para ser solucionados pero para mis necesidades era suficiente.

La reflexión de la línea de fondo puede dar sus frutos si se hace correctamente, y es completamente factible en c++.

 2
Author: Naore Azenkut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-02 23:19:14

Me gustaría anunciar la existencia del kit de herramientas de introspección/reflexión automática "IDK". Utiliza un meta-compilador como Qt y añade información meta directamente en los archivos objeto. 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

 2
Author: Jen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-12 12:49:44

La reflexión en C++ es muy útil, en los casos que hay que ejecutar algún método para cada miembro(Por ejemplo: serialización, hash, comparar). Vine con una solución genérica, con una sintaxis muy simple:

struct S1
{
    ENUMERATE_MEMBERS(str,i);
    std::string str;
    int i;
};
struct S2
{
    ENUMERATE_MEMBERS(s1,i2);
    S1 s1;
    int i2;
};

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 la siguiente manera:

void EnumerateWith(BinaryWriter & writer, int val)
{
    //store integer
    writer.WriteBuffer(&val, sizeof(int));
}
void EnumerateWith(BinaryWriter & writer, std::string val)
{
    //store string
    writer.WriteBuffer(val.c_str(), val.size());
}

Y tenemos la función genérica cerca de la "macro secreta";)

template<typename TWriter, typename T>
auto EnumerateWith(TWriter && writer, T && val) -> is_enumerable_t<T>
{
    val.EnumerateWith(write); //method generated by ENUMERATE_MEMBERS macro
}

Ahora puedes escribir

S1 s1;
S2 s2;
//....
BinaryWriter writer("serialized.bin");

EnumerateWith(writer, s1); //this will call EnumerateWith for all members of S1
EnumerateWith(writer, s2); //this will call EnumerateWith for all members of S2 and S2::s1 (recursively)

Por lo tanto, al tener la macro ENUMERATE_MEMBERS en la definición de la estructura, puede construir serialización, comparar, 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 soportar cualquier tipo en su proyecto.

Esta macro debe tener cero sobrecarga para la creación/destrucción de estructuras en tiempo de ejecución, y el código de T. EnumerateWith() debe generarse bajo demanda, lo que se puede lograr haciendo que sea una función en línea de plantilla, por lo que la única sobrecarga en toda la historia es agregar ENUMERATE_MEMBERS(m1,m2,m3...) para cada estructura, mientras que la implementación de un método específico por tipo de miembro es una necesidad en cualquier solución, por lo que no lo asumo como sobrecarga.

ACTUALIZAR: Hay una implementación muy simple de la macro ENUMERATE_MEMBERS(sin embargo, podría extenderse un poco para admitir la herencia de enumerable struct)

#define ENUMERATE_MEMBERS(...) \
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) const { EnumerateWithHelper(enumerator, __VA_ARGS__ ); }\
template<typename TEnumerator> inline void EnumerateWith(TEnumerator & enumerator) { EnumerateWithHelper(enumerator, __VA_ARGS__); }

// EnumerateWithHelper
template<typename TEnumerator, typename ...T> inline void EnumerateWithHelper(TEnumerator & enumerator, T &...v) 
{ 
    int x[] = { (EnumerateWith(enumerator, v), 1)... }; 
}

// Generic EnumerateWith
template<typename TEnumerator, typename T>
auto EnumerateWith(TEnumerator & enumerator, T & val) -> std::void_t<decltype(val.EnumerateWith(enumerator))>
{
    val.EnumerateWith(enumerator);
}

Y no necesita ninguna biblioteca de terceros para estas 15 líneas de código;)

 1
Author: Evgeny Mamontov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-08 00:53:13

El proyecto Root Reflex tiene soporte para esto.

Véase https://root.cern.ch/how/how-use-reflex

 0
Author: Buğra Gedik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-17 02:15:34

Actualizado 24.2.2017

Anteriormente he analizado el soporte para el uso de #defines y como se recomienda en algunos de los artículos web - He golpeado a través de define en visual C++ no estaban funcionando identically compared to define's used in gcc (for example, on internet this is quite often referred as "MSVC walkaround"). Además de no ser capaz de entender fácilmente lo que está sucediendo detrás de definir / macro maquinaria de expansión - es bastante difícil depurar cada macro expansión.

Hay un par de maneras de caminar alrededor de las complejidades de la expansión de definir, un enfoque es activar la bandera del compilador "/P" (pre-proceso a archivo solamente) - después de eso se puede comparar cómo se abre su definición. (Anteriormente también he utilizado también activamente stringfy operador (#))

He recopilado todas las definiciones útiles de múltiples foros, recurrido a ellas y comentado lo que está sucediendo detrás de machinery, puede encontrar todo el archivo de encabezado aquí ahora:

Https://sourceforge.net/p/testcppreflect/code/HEAD/tree/MacroHelpers.h

Pensé que era bastante trivial usar estas macros para habilitar la reflexión en C++, pero requiere un poco más de magia para hacer la reflexión.

He recogido un código de ejemplo de trabajo, y lo puse como proyecto sourceforge, se puede descargar aquí:

Https://sourceforge.net/p/testcppreflect/code/HEAD/tree /

El código de demostración parece esto:

#include "CppReflect.h"
using namespace std;


class Person
{
public:
    REFLECTABLE( Person,
        (CString)   name,
        (int)       age
    )

};

class People
{
public:
    REFLECTABLE( People,
        (CString) groupName,
        (vector<Person>)  people
    )
};


void main(void)
{
    People ppl;
    ppl.groupName = "Group1";

    Person p;
    p.name = L"Roger";
    p.age = 37;
    ppl.people.push_back(p);
    p.name = L"Alice";
    p.age = 27;
    ppl.people.push_back( p );
    p.name = L"Cindy";
    p.age = 17;
    ppl.people.push_back( p );

    CStringA xml = ToXML( &ppl );
    CStringW errors;

    People ppl2;

    FromXml( &ppl2, xml, errors );
    CStringA xml2 = ToXML( &ppl2 );
    printf( xml2 );

}

REFLECTABLE define usa nombre de clase + nombre de campo con offsetof - para identificar en qué lugar de la memoria se encuentra un campo en particular. He tratado de recoger la terminología de.NET en la medida de lo posible, pero C++ y C# son diferentes, por lo que no es 1 a 1. Todo el modelo de reflexión de C++ reside en las clases TypeInfo y FieldInfo para timebeing, es posible ampliar el soporte también para method, pero he decidido mantener las cosas simples por ahora.

He utilizado pugi xml parser para obtener código de demostración en xml y restaurarlo de nuevo desde xml.

Así que la salida producida por el código de demostración se ve así:

<?xml version="1.0" encoding="utf-8"?>
<People groupName="Group1">
    <people>
        <Person name="Roger" age="37" />
        <Person name="Alice" age="27" />
        <Person name="Cindy" age="17" />
    </people>
</People>

También es posible habilitar cualquier soporte de clase / estructura de 3 partes a través de la clase TypeTraits y la especificación parcial de la plantilla-para definir su propia clase TypeTraitsT, de manera similar a CString o int - ver código de ejemplo en

Https://sourceforge.net/p/testcppreflect/code/HEAD/tree/TypeTraits.h#l65

template <>
class TypeTraitsT<CString> : public TypeTraits
{
public:
    virtual CStringW ToString( void* pField )
    { 
        CString* s = (CString*)pField;
        return *s;
    }

    virtual void FromString( void* pField, const wchar_t* value )
    { 
        CString* s = (CString*)pField;
        *s = value;
    }
};

template <>
class TypeTraitsT<int> : public TypeTraits
{
public:
    virtual CStringW ToString( void* pField )
    {
        int* p = (int*) pField;
        return std::to_string(*p).c_str();
    }

    virtual void FromString( void* pField, const wchar_t* value )
    {
        int* p = (int*)pField;
        *p = _wtoi(value);
    }
};

Supongo que solo la desventaja de mi propia la implementación es el uso de __if_exists, que podría ser una extensión específica del compilador de Microsoft. Si alguien sabe cómo caminar alrededor de él, házmelo saber.

 0
Author: TarmoPikaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-24 22:55:43

La falta de reflexión incorporada en C++ es la única razón por la que C++ moderno no se utiliza para el desarrollo web (y carece de frameworks y otros frameworks)

Puedes probar http://www.extreme.indiana.edu/reflcpp /

 -2
Author: vlad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-15 18:26:36

Una manera simple es usar el operador dynamic_cast<>() que, cuando se asigna a un tipo incorrecto, devuelve NULL, por lo que puede upcast a una clase concreta base de una manera fácil, verificando el valor del puntero, si no es NULL, se realizó el cast, y obtuvo el tipo del objeto.

Pero esto es solo una solución simple, y solo proporciona el tipo de los objetos, no se puede preguntar qué métodos tiene, como en Java. Si necesita una solución avanzada, hay algunos marcos para elegir.

 -4
Author: lurks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 21:42:05