Cualquier macro de C++ que pueda exportar todas las variables miembro de una estructura para pybind11.
Tengo una estructura simple como esta:
“`c++
struct Config {
bool option1;
bool option2;
int arg1;
};
<pre><code>Usando pybind11, debo exportar las variables miembro así:
“`c++
py::class_<config>(m, “Config”)
.def_readwrite(“option1”, &Config::option1)
.def_readwrite(“option2”, &Config::option2)
.def_readwrite(“arg1”, &Config::arg1);
Esto está bien si tengo unas pocas estructuras. Pero se vuelve tedioso cuando tengo un gran número de estructuras simples.
¿Existe una macro conveniente que pueda escribir así?
“`c++
PYBIND_EXPORT_STRUCT(Config1);
PYBIND_EXPORT_STRUCT(Config2);
…
<pre><code>y cada una escanea y exporta todas las variables miembro de la estructura dada?
¿Será útil si ya escribo las estructuras de la siguiente manera?
“`c++
struct Config {
ADD_PROPERTY(bool, option1);
ADD_PROPERTY(bool, option2);
ADD_PROPERTY(int, arg1);
};
Mi pregunta involucra dos partes:
- Reflejar una variable miembro y devolver su cadena de nombre.
- Iterar a través de los miembros de la
struct
.
Soy consciente de la introspección para resolver la primera parte, usando typeid(arg1).name()
para recuperar la cadena de nombre.
Para la segunda parte, C++ no la soporta directamente. Sin embargo, estoy tratando de descubrirlo a través de algunas respuestas aquí.
El resto de la pregunta es cómo fusionar las dos partes anteriores para obtener una implementación de trabajo para mi función imaginada PYBIND_EXPORT_STRUCT()
.
Dicho esto, no me importa expresar mis estructuras de una manera totalmente diferente (como usar macros o como tuplas). Cualquier forma es aceptable, siempre y cuando no tenga que enumerar nuevamente los miembros de mi struct
cuando los exporto con pybind11, y todavía pueda usar las variables como config1.option1 = true
en el código C++.
davy.ai
Para lograr la funcionalidad deseada, podemos escribir una macro que use el preprocesador para generar una lista iterable de los miembros de la estructura y sus nombres correspondientes.
Aquí hay una implementación de ejemplo usando la macro
BOOST_PP_SEQ_FOR_EACH
:“`c++
#include
#define ADD_PROPERTY(type, name) \
type name; \
static constexpr const char* get_name_##name() { return #name; }
#define PYBIND_EXPORT_STRUCT(struct_name) \(m, #struct_name) \
PYBIND11_MODULE(struct_name, m) { \
py::class_
BOOST_PP_SEQ_FOR_EACH(PYBIND_EXPORT_STRUCT_HELPER, ~, \
BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_VARIADIC_SIZE(VA_ARGS), \
BOOST_PP_VARIADIC_TO_TUPLE(VA_ARGS))); \
} \
BOOST_PP_SEQ_FOR_EACH(PYBIND_EXPORT_STRUCT_MEMBER, struct_name, \
BOOST_PP_TUPLE_TO_SEQ(BOOST_PP_VARIADIC_SIZE(VA_ARGS), \
BOOST_PP_VARIADIC_TO_TUPLE(VA_ARGS)));
#define PYBIND_EXPORT_STRUCT_HELPER(r, data, elem) \
.def_readwrite(#elem, &data::elem)
#define PYBIND_EXPORT_STRUCT_MEMBER(r, struct_name, elem) \
constexpr const char* struct_name####elem##_name = \
struct_name::get_name##elem();
Esto generará el código necesario para exportar la estructura
Config
y producir una lista de sus nombres de miembros:“`c++(m, “Config”)
// código generado
PYBIND11_MODULE(Config, m) {
py::class_
.def_readwrite(“option1”, &Config::option1)
.def_readwrite(“option2”, &Config::option2)
.def_readwrite(“arg1”, &Config::arg1)
;
}
constexpr const char* Config_option1_name = Config::get_name_option1();
constexpr const char* Config_option2_name = Config::get_name_option2();
constexpr const char* Config_arg1_name = Config::get_name_arg1();
“`
Tenga en cuenta que esta implementación supone que todos los miembros de la estructura son públicos y que sus tipos se pueden usar directamente con pybind11. Si no es así, pueden ser necesarias algunas modificaciones adicionales.