2009-05-21 21 views
33
atención

de pago con cuidado porque este es un infierno de una pregunta ;-)La programación funcional en C con macro generadores "Superior" función de orden

quiero usar las funciones de plantilla para las acciones de cobro genéricos (como la búsqueda, foreach, etc. .) en C mientras se mantiene la comprobación del tipo estático del compilador. Es bastante sencillo, mientras que usted está utilizando las devoluciones de llamada simples, como en este ejemplo:

#define MAKE_FOREACH(TYPE)\ 
void foreach_##TYPE (TYPE[n] array, int n, void(*f)(TYPE)) {\ 
    for(int i = 0; i < n; i++) {\ 
    f(array[i]);\ 
    }\ 
} 

para que pueda hacer cosas como:

MAKE_FOREACH(int) 
MAKE_FOREACH(float) 

void intcallback(int x){ 
    printf("got %d\n", x); 
} 

void floatcallback(float x){ 
    printf("got %f\n", x); 
} 

int main(){ 
    int[5] iarray = {1,2,3,4,5}; 
    float[5] farray = {1.0,2.0,3.0,4.0,5.0}; 
    foreach_int(iarray, 5, intcallback); 
    foreach_float(farray, 5, floatcallback); 
} 

Si Me gustaría poner en práctica las devoluciones de llamada con tipos de retorno, para ejemplo para hacer una función de "mapa", podría hacer:

#define MAKE_MAP(TYPE, RTYPE)\ 
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE)) {\ 
    RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\ 
    for(int i = 0; i < n; i++) {\ 
    result[i]=f(array[i]);\ 
    }\ 
} 

Hasta ahora, muy bien. El problema viene ahora, cuando quiero que mis funciones de devolución de llamada acepten cualquier cantidad de argumentos escritos.

La idea es algo así como:

#define MAKE_MAP(TYPE, RTYPE, ...)\ 
RTYPE* map_##TYPE (TYPE[n] array, int n, RTYPE(*f)(TYPE, __VA_ARGS__), __VA_ARGS__) 
/*this would work for the declaration (because just the types would be enough) 
but the parameter names are missing :-s*/ \ 
{\ 
    RTYPE* result = (RTYPE*)malloc(sizeof(RTYPE)*n);\ 
    for(int i = 0; i < n; i++) {\ 
    result[i]=f(array[i], /*here the names of the parameters, in order*/);\ 
    }\ 
} 

así, como se puede ver, pude declarar una función de mapa como:

MAKE_MAP(int, float, char) 

dando:

float* map_int(int[n] array, int n, float(*f)(int, char), char); 

pero no puedo entender cómo implementar el parámetro que pasa con el preprocesador. Aquí es donde pido su ayuda, ideas y sugerencias.

(Por cierto, no me diga que utilizar una función variadic como plantilla y pasar un argumento va_list a la devolución de llamada, porque todo esto era debido a la :-p chequear el tipo)

+17

¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡SI QUIERO EMPUJAR UN POCO MÁS PEQUEÑO, ESTE PEGÓGENO CUADRADO SE ME ENCUENTRE EN MI AGUJERO REDONDO !!!! – mquander

+3

Felicitaciones por etiquetar este "preprocesador-abuso". Estoy pensando en cómo escribiría una macro MAKE_PROGRAM(). –

+7

Este ciertamente * es * abuso de preprocesador, pero ¿no es la meta-programación de plantillas tan de moda realmente solo el abuso del sistema de plantillas de C++ también? A veces la única respuesta sensata * es * para empujar la herramienta al borde de su usabilidad. – RBerteig

Respuesta

12

Si son en Linux/Unix BSD, echar un vistazo a queue(3) y registro en /usr/include/sys/queue.h - que se ha hecho antes :)

+0

gracias! parece ser la mejor solución hasta el momento :-) – fortran

+0

Y se usa en todas las fuentes del núcleo (s), por lo que funciona :) –

+0

http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.4 BSD/usr/include/sys/queue.h –

1

Para información, el código fuente de GCC 4.6 implementa trucos similares para vectores. Mire en su archivo gcc/vec.h

Cuestiones relacionadas