2009-05-21 6 views
33

Attenzione attenzione perché questo è un inferno di una domanda ;-)programmazione funzionale in C con macro generatori "Higher funzione Order"

Voglio utilizzare le funzioni di modello per le azioni di raccolta generici (come la ricerca, foreach, ecc .) in C mantenendo il controllo del tipo statico del compilatore. E 'abbastanza semplice, mentre si sta utilizzando callback semplici come in questo esempio:

#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]);\ 
    }\ 
} 

modo da poter fare le cose come:

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); 
} 

Se mi piacerebbe implementare callback con i tipi di ritorno, per esempio per fare una funzione "mappa", potrei fare:

#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]);\ 
    }\ 
} 

Finora, tutto bene. Il problema arriva ora, quando voglio che le mie funzioni di callback accettino un numero qualsiasi di argomenti digitati.

L'idea è qualcosa di simile:

#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*/);\ 
    }\ 
} 

modo, come potete vedere, ho potuto dichiarare una funzione mappa come:

MAKE_MAP(int, float, char) 

dando:

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

ma non riesco a capire come implementare il parametro che passa con il preprocessore. Qui è dove chiedo il tuo aiuto, idee e suggerimenti.

(A proposito, non dirmi di usare una funzione di variadic come modello e passando un argomento va_list al callback, perché tutta questa roba era a causa del tipo :-p controllo)

+17

FORSE SE SOLO UN PICCOLO HARDER QUESTO SQUARE PEG SI ADATTA AL MIO FORO ROTONDO !!!! – mquander

+3

Complimenti per l'etichettatura di questo "abuso del preprocessore". In questo momento sto pensando a come scrivere una macro MAKE_PROGRAM(). –

+7

Questo * è * l'abuso del preprocessore, ma non è la meta-programmazione del modello così alla moda che solo l'abuso del sistema di template in C++? A volte l'unica risposta sensata * è * spingere lo strumento al limite della sua usabilità. – RBerteig

risposta

12

Se sono su Linux/BSD Unix, dare un'occhiata a queue(3) e controllare in /usr/include/sys/queue.h - è stato fatto prima :)

+0

grazie! sembra la soluzione migliore finora :-) – fortran

+0

E viene utilizzata in tutto il kernel (s), quindi funziona :) –

+0

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

1

Per informazioni, il codice sorgente di GCC 4.6 implementa trucchi simili per i vettori. Guarda nel suo file gcc/vec.h