2010-03-20 16 views

Respuesta

14

Esa es una pregunta muy amplia. Fundamentalmente, un cierre es un puntero de instrucción junto con algún contexto almacenado que se requiere para ejecutar las instrucciones de la manera correcta. Ciertamente puedes juntar algo como esto en C usando estructuras y punteros de función.

Digamos que usted expresa un cierre que toma dos enteros y devuelve vacío como una estructura:

typedef struct VoidClosureIntInt { 
    void (*fn)(int, int); 
    int first; 
    int second; 
} VoidClosureIntInt; 

y supongamos que tiene una función:

void Foo(int x, int y); 

Ahora, para crear un cierre que se invocar a Foo (23, 42), lo haría:

VoidClosureIntInt closure = {&Foo, 23, 42}; 

Y luego, para ejecutar más tarde ese cierre, lo haría hacer:

(*closure.fn)(closure.first, closure.second); 

Una arruga más: la mayoría de las veces cuando se está utilizando cierres, que desea pasar contexto en torno allá de la vida del bloque de código en el que se crea el cierre. (Ejemplo: está pasando el cierre a una función que realiza algunas E/S asíncronas y eventualmente llamará a su cierre cuando termine la E/S). En tales casos, debe asegurarse de asignar su cierre en el montón, y eliminar su cierre cuando haya terminado con él. (Ver el ejemplo completo en la parte inferior).

Una nota final: obviamente hay una gran cantidad de máquinas aquí, y es sólo para un tipo de cierre (una función que toma dos argumentos enteros y devuelve void). Cuando he visto esto hecho en C, a menudo lo hace un generador de códigos que crea maquinaria para muchos tipos diferentes de cierres. También puede reducir la cantidad de texto repetitivo solo apoyando cierres que toman algunos (número fijo de) argumentos nulos * y luego encasilla dentro de las funciones que está utilizando para implementar esos cierres.

Si está en C++, puede aprovechar las funciones de idioma para hacer esto de manera mucho más genérica y con mucho menos tipeo. Ver Boost.Function para un ejemplo.

ejemplo completo:

#include <stdio.h> 
#include <stdlib.h> 

// Closure support. 

typedef struct VoidClosureIntInt { 
    void (*fn)(int, int); 
    int first; 
    int second; 
} VoidClosureIntInt; 

// The returned closure should be run via RunAndDeleteClosure(). 
VoidClosureIntInt* NewClosure(void (*fn)(int, int), int first, int second) { 
    VoidClosureIntInt* closure = malloc(sizeof(*closure)); 
    closure->fn = fn; 
    closure->first = first; 
    closure->second = second; 
    return closure; 
} 

void RunAndDeleteClosure(VoidClosureIntInt* closure) { 
    (*closure->fn)(closure->first, closure->second); 
    free(closure); 
} 


// Example use. 

void Foo(int x, int y) { 
    printf("x=%d\ny=%d\n", x, y); 
} 

// We take memory ownership of closure. 
void SomeAsynchronousFunction(VoidClosureIntInt* closure) { 
    RunAndDeleteClosure(closure); 
} 

int main(int argc, char** argv) { 
    VoidClosureIntInt* closure = NewClosure(&Foo, 23, 42); 
    SomeAsynchronousFunction(closure); 
    return 0; 
} 
-1

Respuesta simple:

NO

En este momento, a menos que reducir esto a una especie de muy pequeño subconjunto de la funcionalidad de los cierres, que es como es.

+0

Siempre pensó en cierres siendo un concepto atómica; ¿Cómo lo subconjiste? – Pierreten

+0

Will Robinson parece tener un muy buen ejemplo de esto, por lo que esta respuesta es incorrecta. –

+0

Robinson está mostrando un montón de código para implementar 'un pequeño (y no muy útil) subconjunto de cierres'. – bmargulies

-1

supongo que depende de lo que su idea de "simple" es.

Existen varias implementaciones de esquema que están diseñados para integrarse como un lenguaje de extensión para los programas C. Enlace en un Esquema, escriba su cierre en Scheme, y listo.