2011-02-07 21 views
5

Tengo este problema donde se guarda un puntero de función C++, junto con un conjunto de argumentos para invocarlo, de modo que se pueda llamar más tarde. El código de llamada desconoce el tipo y los argumentos de las funciones. Guardar y llamar punteros a función y argumentos es extremadamente crítico para el rendimiento en mi aplicación. La interfaz debe ser algo como esto:Puntero de función de guardado + argumentos para su uso posterior

void func(int a, char * b); 
call_this_later(func, 5, "abc"); 

Una solución sencilla es poner toda esta información en un funtor, lo que requiere un typedef diferente por cada llamada de función. C++ 11 me permitiría hacer eso usando una plantilla variadica, así que eso está bien.

Como no se conoce el tipo de functor en el punto de llamada, parece necesario crear una clase base virtual para estos funtores e invocar a los funtores mediante llamadas a funciones virtuales. La sobrecarga de rendimiento de las llamadas a funciones virtuales + la asignación de heap es demasiado alta (estoy ampliando los límites de la implementación de este modismo con las pocas instrucciones de ensamblaje posibles). Entonces necesito una solución diferente.

¿Alguna idea?

Respuesta

0

Necesitará un asignador personalizado para que coincida con su patrón de asignación. Alternativamente, utilice el polimorfismo en tiempo de compilación para pasar el tipo de functor al sitio de llamadas.

3

¿Qué pasa con una solución utilizando boost::function/boost::bind:

void func(int a, char * b); 

boost::function<void()> my_proc = 
    boost::bind(&func, 5, "abc"); 

// then later... 

my_proc(); // calls func(5, "abc"); 
+1

Creo que ':: boost :: function' y' :: std :: tr1 :: function' hacen exactamente lo que @Hans no quiere hacer. Creo que usan funciones virtuales y asignación dinámica. – Omnifarious

+0

@Omnifarious: depende de la función/functor utilizado en cuanto a si hay alguna asignación dinámica. para funciones con un pequeño número de tipos de POD, hay un almacenamiento interno que usará; sin embargo, sí hace uso de una tabla virtual (muy profunda) oculta para poder realizar la llamada a la función. – diverscuba23

2

Se puede hacer esto con una expresión lambda que captura los tipos.

template <typename Func, typename Arg1, typename Arg2> 
std::function<void(void)> call_this_later(Func f, Arg1 a1, Arg2 a2) { 
    return [=]() { f(a1, a2); }; // Capture arguments by value 
} 

Algunas cosas para tomar nota:

  1. no creo que se puede utilizar el desvío perfecta aquí ya que tienes que capturar los argumentos
  2. Puesto que C++ no es recolección, si los argumentos son indicadores que pueden señalar algo que no está vivo más adelante. Por ejemplo, si su argumento es const char*, entonces está bien si lo usa con una cadena literal, pero no si pasa someStdString.c_str() y la cadena va a desaparecer pronto.
  3. Di el ejemplo con dos argumentos, si su compilador admite plantillas variadic, puede usar los demás; de lo contrario, cree una sobrecarga para cada número de argumentos.
Cuestiones relacionadas