Llamar a una función desde una cadena con el nombre de la función en C ++

¿Cómo puedo llamar a una función de C ++ desde una cadena?

En lugar de hacer esto, llame al método directamente desde la cadena:

void callfunction(const char* callthis, int []params) { if (callthis == "callA") { callA(); } else if (callthis == "callB") { callB(params[0], params[1]); } else if (callthis == "callC") { callC(params[0]); } } 

En C # usaríamos typeof () y luego obtendríamos la información del método y llamaremos desde allí … ¿algo que podamos usar en C ++?

Crea un std :: map hecho de cadenas y punteros de función. Cree el mapa con todas las funciones que desea llamar.

Hay otras formas de hacerlo, que incluyen tablas de símbolos y cargadores dynamics, pero esas formas no son portátiles ni amigables.

Otras soluciones son variaciones sobre el mismo tema:

 switch (callthis) { case FUNCA: callA(); break; case FUNCB: callB(params); break; ... etc. } 

O busca una serie de estructuras:

 struct { char *name; TFunc f; } funcdefs [] = { {"callA", callA}, {"callB", callB}, {"callC", callC}, ... etc. {NULL, NULL} }; for (int j = 0; funcdefs [j] .name; ++j) if (!strcmp (funcdefs [j] .name, callthis)) { funcdefs [j] .f (params); break; } 

También puede ver las respuestas a ¿Cómo puedo agregar reflexión a una aplicación de C ++? Para información sobre RTTI, el mecanismo de reflexión en C ++.

Buena suerte.

Alternativa: podría usar una matriz de punteros de función y llamar a la función deseada utilizando su índice.

 typedef void (*TFunc)(int, int); TFunc arrptr[100]; void callFunction(int index, int params[]) { (*arrptr[index])(params[0], params[1]); } 

Puede que no sea una opción, pero si puede usar c ++ administrado (C ++ / CLI), puede hacer esto como lo hace en C #. Esto requerirá .NET aunque …

No hay una buena manera de hacer automáticamente lo que pides. Consideraría dos formas diferentes, dependiendo de cuántas funciones crees que necesitarán ser llamadas:

Si solo hay unas pocas funciones, quédese con el código que tiene (tenga en cuenta que si desea usar const char *, no puede comparar estas cadenas con el operador ==. Puede usar “strcmp ()” haciendo lo siguiente: un “#include “).

Si habrá muchas funciones, o si agregará y eliminará funciones de su lista con frecuencia, es posible que desee usar “std :: map”. Esto asignará la cadena de nombre de función a un puntero de función. Probablemente envolvería esto en una clase para facilitar su uso:

 class Str2Fun { std::map data; public: void add( const char *funName, (void*)(int**) funPtr ); void call( const char *funName ); }; 

imposibilidad general

En el estándar C ++ 11 puro, realmente no puede lograr ese objective (llamar a una función desde su nombre, dado por alguna cadena arbitraria en tiempo de ejecución) fácilmente, si desea llamar a cualquier función arbitraria posible de su progtwig (o de las bibliotecas utilizadas por it) del nombre de la función. De hecho, podría incluir un intérprete (por ejemplo, Lua o GNU guile ), como sugiere la respuesta de xtofl .

Mantener una asociación de nombre a funciones.

Si conoce el conjunto de funciones potencialmente invocables, y si comparten una firma común (por ejemplo, typedef int signature_T(int[]) , puede usar simplemente una asociación de nombres a funciones, por ejemplo, std::map> ; Por cierto, las nuevas funciones de C ++ 11 (cierres, std::function , auto , lambdas) deberían ayudar mucho.

utilizando recursos dynamics de enlace como dlsym en POSIX

Si se restringe a un sistema POSIX como Linux, podría considerar algún otro truco: use dlsym (3) y dlopen (3) para obtener un puntero a función de algún nombre no enredado . Así que declararía las funciones a las que desea llamar a través de su nombre como extern "C" (para deshabilitar la manipulación de nombres ), vincularía su progtwig con -rdynamic y con la biblioteca -ldl . Puede cargar dinámicamente sus complementos con dlopen -o obtener el controlador principal del progtwig con dlopen -ing dlopen y obtener un puntero de función desde su nombre usando dlsym . Lea C ++ dlopen mini howto y el documento Cómo escribir bibliotecas compartidas de Drepper.

(Windows también tiene instalaciones casi equivalentes a dlsym ya que también tiene un enlazador dynamic ; pero nunca usé Windows)

Algunas bibliotecas de marcos de C ++ ( Qt , POCO ) están envolviendo la carga dinámica de complementos de forma independiente del sistema operativo.

llamando a funciones arbitrarias usando libffi

Hay un problema relacionado con las funciones de llamada de la firma arbitraria . Es absolutamente necesario conocer la firma (al menos en tiempo de ejecución y, a menudo, en tiempo de comstackción) al llamar a cualquier función en (o desde) C o C ++ (porque el ABI dicta varias convenciones de llamada ). Podrías usar el libffi :

Es posible que algunos progtwigs no sepan en el momento de la comstackción qué argumentos deben pasarse a una función. Por ejemplo, a un intérprete se le puede decir en tiempo de ejecución sobre el número y los tipos de argumentos utilizados para llamar a una función determinada. Libffi se puede utilizar en dichos progtwigs para proporcionar un puente desde el progtwig de intérprete al código comstackdo.

Generación Just-In-Time de código de máquina

Por último, podría generar algún código de máquina en tiempo de ejecución utilizando alguna biblioteca JIT : bibliotecas JIT simples como GNU lightning , libjit , asmjit son capaces de generar rápidamente un código de máquina bastante lento, o marcos JIT complejos basados ​​en comstackdores como libgccjit o LLVM , que son generar código de máquina optimizado y rápido (pero necesita un tiempo de generación significativo, como un comstackdor).

generar C (o código C ++) en tiempo de ejecución, comstackrlo y dlopen -ing

Un truco relacionado simplemente generaría algo de código C o C ++ en un archivo temporal /tmp/foobar.c , bifurca una comstackción de este en un complemento (así que solicite un código independiente de la posición ) con gcc -fPIC -O -shared /tmp/foobar.c -o /tmp/foobar.so , luego cargue dinámicamente ese complemento temporal usando dlopen . Estoy usando ese truco en MELT (un lenguaje específico del dominio Lispy para extender y personalizar GCC , el software gratuito disponible GPLv3). En la práctica, los comstackdores son lo suficientemente rápidos hoy en día para permitir incluso dicho uso de manera interactiva: el usuario podría escribir una expresión simple en algunos DSL, la infraestructura está traduciendo ese código de DSL a C y luego comstackndo la comstackción de ese código en un complemento que luego se dlopen . ed. Esto es lo suficientemente rápido en la práctica para el uso interactivo (ya que el código C generado tendría unos pocos cientos de líneas por expresión interactiva, y la comstackción toma una fracción de segundo).

otros lenguajes de progtwigcion

Algunos lenguajes de progtwigción son homoicónicos y / o tienen alguna facilidad de eval , o habilitan la progtwigción de múltiples etapas . Algunas implementaciones tienen incluso la capacidad de generar código de máquina bastante eficiente en tiempo de ejecución, en particular, SBCL siempre está traduciendo a código de máquina cada expresión, incluso en su ciclo de lectura-evaluación-impresión .

Podrías envolver tus declaraciones de funciones en un lenguaje interpretado (como Lua o Perl o Python (boost tiene un marco agradable para eso) ). Luego usa ese lenguaje para llamar a tu código ‘por cadena’.

Estos lenguajes / envoltorios están diseñados para hacer tales cosas. C ++ no lo es, por lo que se esforzará mucho en agregar soporte para él.