2012-06-25 21 views
6

He estado trabajando con libffi últimamente, y dado que utiliza una API C, cualquier abstracción se realiza mediante el uso de punteros vacíos (buena ol 'C). Estoy creando una clase (con plantillas variadic) que utiliza esta API. La declaración de la clase es la siguiente: (en la que Ret = valor de retorno y Args argumentos = función)Plantillas variables: iterar sobre el argumento de tipo/plantilla

template <typename Ret, typename... Args> 
class Function 

Dentro de esta clase tengo dos funciones diferentes declararon también (simplificado):

Ret Call(Args... args); // Calls the wrapped function 
void CallbackBind(Ret * ret, void * args[]); // The libffi callback function (it's actually static...) 

quiero para poder usar Call de CallbackBind; y ese es mi problema No tengo idea de cómo se supone que debo convertir la matriz void* a la lista de argumentos con plantilla. Esto es lo que yo quiero, más o menos:

CallbackBind(Ret * ret, void * args[]) 
{ 
// I want to somehow expand the array of void pointers and convert each 
// one of them to the corresponding template type/argument. The length 
// of the 'void*' vector equals sizeof...(Args) (variadic template argument count) 

// Cast each of one of the pointers to their original type 
*ret = Call(*((typeof(Args[0])*) args[0]), *((typeof(Args[1])*) args[1]), ... /* and so on */); 
} 

Si esto no es posible, hay soluciones provisionales o diferentes soluciones disponibles?

+1

¿Hay alguna razón por la que no pueda simplemente llamar directamente a la API de la biblioteca desde la devolución de llamada? Ya tiene un 'void *', y ya lo espera. –

+0

Mmm ¿por qué quieres llamar a una función de plantilla variadic con una cantidad fija de argumentos? Basado en el hecho de que "la longitud de args es igual a sizeof ... (Args)", entonces sabes el número de argumentos requeridos, ¿por qué usar plantillas variadic ?. – mfontanini

+0

@MarkB Dado que 'CallbackBind' se llama _from_ de la API de la biblioteca, intento llamar a mi propia función que no utiliza punteros vacíos. @mfontanini Quiero una clase que imita 'std :: function', y por lo tanto necesito plantillas variadas (como' operator() (Args ...) ') –

Respuesta

5

No desea iterar sobre los tipos, desea crear un paquete de parámetros y expandirlo en una plantilla variadic. Tienes una matriz, por lo que el paquete que deseas es un paquete de enteros 0,1,2 ... para servir como índices de matriz.

#include <redi/index_tuple.h> 

template<typename Ret, typename... Args> 
struct Function 
{ 
    Ret (*wrapped_function)(Args...); 

    template<unsigned... I> 
    Ret dispatch(void* args[], redi::index_tuple<I...>) 
    { 
    return wrapped_function(*static_cast<Args*>(args[I])...); 
    } 

    void CallbackBind(Ret * ret, void * args[]) 
    { 
    *ret = dispatch(args, to_index_tuple<Args...>()); 
    } 
}; 

Algo por el estilo, utilizando index_tuple.h

El truco es que CallbackBind crea una index_tuple de números enteros que representan las posiciones arg, y despachos a otra función que deduce los números enteros y se expande el paquete en una lista de yeso expresiones para usar como argumentos para la función envuelta.

+0

¡Qué solución tan elegante! Funcionó a la perfección para mí. –