example - Programación funcional en C con generadores de macro "Función de orden superior"
gcc macros (3)
Presta atención con atención porque esta es una gran pregunta ;-)
Deseo utilizar funciones de plantilla para acciones de recopilación genéricas (como búsqueda, foreach, etc.) en C mientras mantengo la comprobación del tipo estático del compilador. Es bastante sencillo cuando usa 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 quisiera implementar devoluciones de llamada con tipos de devolución, por ejemplo para hacer una función de "mapa", podría hacer lo siguiente:
#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 aquí todo 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*/);/
}/
}
entonces, como pueden ver, podría 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 imaginar 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 use una función variadica como plantilla y pase un argumento va_list a la devolución de llamada, porque todo esto fue debido a la verificación de tipo :-p)
Para información, el código fuente de GCC 4.6 implementa trucos similares para vectores. Mire en su archivo gcc/vec.h
Si está en Linux / BSD Unix, eche un vistazo a la queue(3) y compruebe en /usr/include/sys/queue.h
- ya se ha hecho antes :)
Una pregunta reciente planteó bastantes bibliotecas de abuso de preprocesadores desvergonzados.