2010-01-22 8 views
6

Por extraño que suene, necesito llamar a una función en C++, para la cual no conozco la firma. Básicamente, quiero permitir que el usuario especifique una lista de argumentos y tipos de argumentos, y luego intente llamar a una función dada con estos argumentos. Me gustaría saber si la llamada a la función funcionó o no, y si lo hizo (milagrosamente), cuál es el valor de retorno (siempre que el tipo de devolución no sea nulo). ¿Hay alguna manera de lograr eso? Gracias.Llamada a la función C++ con los parámetros desconocidos en tiempo de compilación

+5

Creo que una pregunta importante es * "¿Por qué?" * Probablemente haya una manera mucho más simple. – GManNickG

+0

¿Siempre llamarás a la misma función? ¿O la lista de argumentos/parámetros selecciona la función que se llamará? –

+0

Sí, parece que tienes algo que realmente quieres hacer con este pequeño experimento mental. ¿Qué es? – Omnifarious

Respuesta

0

No suena demasiado raro, pero todavía no puede hacerlo en C++. Las firmas de funciones de C++ se comprueban en tiempo de compilación. Lo mejor que puede hacer es pasar un vector, o contenedor similar, que contenga los parámetros de su función a la función. Incluso entonces, los tipos (o al menos el tipo de base, si utiliza herencia) tendrían que conocerse en tiempo de compilación.

+0

@Neil Butterworth: Su conclusión podría ser correcta, pero su razonamiento es falaz. Lo mismo ocurre con C# (tipado estáticamente), pero es posible hacer lo que el OP está solicitando allí utilizando la reflexión. Sí, sé que C++ no tiene capacidades de reflexión. – jason

+1

Por supuesto. C++ le permite hacer cualquier cosa, pero ¿con qué esfuerzo? Parece poco probable que el OP desee escribir un mecanismo de reflexión de propósito general para C++. –

+0

@Neil Butterworth: Estoy de acuerdo con eso. Y la pregunta sugiere un gran olor a diseño. – jason

0

Si tiene acceso al compilador C++ durante el tiempo de ejecución, puede escribir la llamada postulada en un archivo, compilarla, vincularla dinámicamente como una DLL e intentar ejecutarla. Si los tipos de argumento son incorrectos o la función no existe, el enlace de tiempo de ejecución de DLL falla; de lo contrario, se llama a la función y obtienes el valor de retorno.

5

Deje que sus funciones tomen una lista de tipos de datos variantes, p. std::vector<boost::any> y hacer que devuelvan un bool indicando éxito o lanzar excepciones en caso de falla.

Si está de acuerdo con el registro de las funciones expuestas en tiempo de compilación, ni siquiera tiene que poner esa restricción en sus funciones y en su lugar puede generar código de cola para las conversiones necesarias.

+0

+1 boost :: variant también podría usarse –

+0

Y si su función necesita devolver valores de diferentes tipos, devuelva una variante. O algún otro tipo discriminado. Boost no es obligatorio. Podrías enrollar algo para tus necesidades específicas con bastante facilidad. –

+1

Es decir, una 'unión'. Creo que 'variant' sería una muy buena idea, hablando ... MUY relativamente. – Potatoswatter

3

Por supuesto que puede hacer eso en tiempo de ejecución. Gdb, por su parte, lo hace. Pero requiere mucho trabajo y comprensión del entorno objetivo. Sospecho que podría haber una mejor manera de hacer lo que quieres.

+1

Gdb no lo hace "en C++", sin embargo.La "comprensión del entorno objetivo" cambia radicalmente el problema. –

0

Bueno, si eres flexible con el mechanisim, puedes hacer este tipo de cosas mediante el envío dinámico.

Lo que debes hacer es crear una clase base abstracta que tenga un método "ejecutarlo" que devuelva un valor de retorno. Luego tiene un motor que mantiene una lista de punteros a los objetos de esta clase base (abstracta), que los clientes pueden proporcionarle mediante algún tipo de llamada de registro.

Los clientes escriben sus propias implementaciones de "ejecutarlo" que pueden hacer lo que sea necesario, siempre y cuando llenen correctamente el valor de retorno de su motor cuando hayan terminado. Sus "parámetros personalizados" se implementan como miembros adicionales a su versión de la clase, que se pueden completar cuando construyen el objeto o mediante una llamada por separado.

Esto le brinda lo que necesita para llamar a su rutina, ejecutarla y verificar el resultado, sin tener que saber cuáles son sus parámetros personalizados, o qué hace exactamente su rutina.

-1

Esto suena como una niñera para incluir un lenguaje de scripting de tipo dinámico en su aplicación. Incruste algo así como Lua o Python, haga que las funciones que desea invocar estén disponibles para el lenguaje de scripting. O bien, si está intentando implementar algo así, consulte Boost :: Python para obtener un precedente de cómo hacerlo.

0

Ésta es una pregunta sin sentido, ya que si el usuario (quién está llamando desde c-código) no conoce los tipos de argumento en tiempo de compilación, se le no ser capaz de suministrar los argumentos de la tipo correcto, incluso si fuera posible construir un puntero de función tipeado dinámicamente.

Incluso el ejemplo gdb expresado en otra respuesta supone que el usuario tiene variables del tipo apropiado y conocido en el punto de la llamada.

Como esto es cierto, deduzco que el usuario conoce los tipos correctos del argumento, y esto se convierte en una cuestión de cómo crear una función en tiempo de compilación que tome un conjunto de argumentos de tipo conocido.

esto se consigue simplemente: Si el usuario tiene una int y dos float s y espera obtener una int a cambio, y desea llamar a la supuesta función swizzle cuyo tipo por lo tanto debe ser int (IIIF*)(int, int, float), entonces simplemente declarar un puntero de esta escriba, use ldload para obtener la función swizzle, e iníciela.

Existen, sin embargo, algunos casos especiales de esto que puede lograr, por ejemplo, si todos los argumentos son punteros.

Tenga en cuenta que conocido en tiempo de compilación incluye casos como plantillas, cuyos valores son inferidos en tiempo de compilación de información de tipo explícito o implícito en el momento de instancias punto y la plantilla.

0

¿Qué le parece usar las referencias de rvalue en C++ ox?

template<typename Function> 
void FunCall(Function&& f) 
{ 
    f(); 
} 

void Fun_Int(int x) 
{ 
    using std::cout; 
    using std::endl; 

    cout << "I''m Fun_Int with " << x << endl; 
} 

void Fun_Str(const string& str1) 
{ 
    using std::cout; 
    using std::endl; 
    cout << "I'm Fun_Str with " << str1 << endl; 

} 

void RvaluesDemo() 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     FunCall([&] 
     { 
      Fun_Int(i); 
     }); 
    } 

    string str = "ABCDEF"; 

    for (int i = 0; i < str.size(); i++) 
    { 
     ostringstream os; 
     os << str[i]; 

     FunCall([&] 
     { 
      Fun_Str(os.str()); 
     }); 
    } 
} 
Cuestiones relacionadas