2010-11-10 10 views
25

Me he preguntado si es posible convertir un C++ 0x lambda en un bloque clang. Hasta ahora, todo lo que he visto en él ha involucrado la discusión entre sus diferencias. Mi razón principal para investigar esto es hacer una envoltura eventual para libdispatch, y si bien estoy al tanto de las funciones dispatch_*_f, cualquier información sobre su uso ha sido bastante deficiente, en comparación con su homólogo de bloque.¿Es posible convertir un C++ 0x lambda en un bloque clang?

Hasta ahora he podido encontrar información sobre converting a C++ lambda to a function pointer, pero esto es más en el sentido inverso.

Si alguien sabe algo relacionado con esto, y podría proporcionar un enlace, o al menos apuntarme en la dirección correcta, realmente lo agradecería. (incluso una respuesta "Esto no es posible actualmente" será suficiente)

+0

Por cierto, su título pide convertir lambda -> clang block, pero su pregunta pide convertir el bloque -> lambda. –

+0

Gracias, lo arreglé ahora :) –

Respuesta

12

Un parche que permite esta conversión implícitamente acaba de agregarse a clang trunk.

+1

Con url: [http://llvm.org/viewvc/llvm-project?view=rev&revision=150620](http://llvm.org/viewvc/llvm-project?view = rev & revision = 150620) –

+0

Acabo de ver la página que se encuentra en el sitio web clang que detalla cómo funciona esto, así que estoy marcando esto como la respuesta. –

2

No creo que una conversión real sea posible. A diferencia del caso inverso, deshacerse del bloque clang original tiene algunos efectos secundarios de los que no puedes recuperarte. Mientras que C++ 0x lambdas puede capturar variables por referencia, no se hace nada especial para asegurarse de que la variable original todavía esté allí cuando realmente pretenda usar la lambda. Los bloques, por otro lado, pueden interactuar con las variables declaradas con el calificador de almacenamiento __block, en cuyo caso estas variables se mantendrán en la memoria (incluso si eso significa que se copiarán de la pila al montón) mientras viva (incluidas las copias realizadas) por Block_copy):

__block variables que viven en el almacenamiento que se comparte entre el ámbito léxico de la variable y todos los bloques y el bloque ejemplares declarados o creados dentro de ámbito léxico de la variable . Por lo tanto, el almacenamiento sobrevivirá la destrucción del marco de pila si cualquier copia de los bloques declaradas dentro del marco sobreviven más allá del final de la trama (por ejemplo, por estar en cola algún lugar para su posterior ejecución).

Por lo tanto, a menos que la intención de mantener el bloque original alrededor (y por lo tanto envolver en lugar de convertirla), algunas de sus funciones originales serán desaparecidos como los __block variables se han ido.

Sin embargo, no soy un experto en los temas y me gustaría escuchar otras opiniones :)

0

Bueno, Clang todavía no soporta lambdas, y tampoco lo hace el CCG Apple. Los GCC de FSF lo suficientemente recientes como para admitir lambdas no son compatibles con los bloques AFAIK. Entonces, la cuestión de la conversión entre ellos aún no se aplica.

Una vez Clang admite ambos, puede haber una forma en el modo ObjC++ para convertir entre ellos.

6

En general, cuando se utiliza lambda para el cierre "hacia abajo", se puede convertir un C++ lambda a un bloque de sonido metálico mediante la conversión:

[&](int i) { return i; } 

a:

^(int i) { return i; } 

Todavía hay algunas sutiles diferencias Los bloques de Clang solo capturan las clases de C++ mediante const. No sé si esto incluye los tipos de C++ POD también.

Finalmente, si se necesita un cierre "hacia arriba", los dos divergen drásticamente.Los bloques de Clang requieren que las variables capturadas se anoten con __block, que el compilador asignará en el montón. Mientras que, en C++, la forma en que la lambda captura, necesita ser decidida en base a la vida del objeto. (Eso es por valor haciendo una copia o por referencia).

También en C++, copiar el cierre es manejado automáticamente por el mecanismo de copia y constructor en C++. Sin embargo, con el bloqueo de clang, es necesario llamar a Block_copy y Block_release para gestionar la copia del bloque. Se puede escribir un contenedor simple en C++ para manejar esto. Por ejemplo:

typedef void (^simple_block)(void); 
class block_wrapper 
{ 
    simple_block block; 

public: 
    block_wrapper (const simple_block& x) 
    : block(Block_copy(x)) {} 

    void operator()() const 
    { 
    block(); 
    } 

    block_wrapper(const block_wrapper& rhs) 
    : block(Block_copy(rhs.block)) 
    {} 

    block_wrapper& operator=(const block_wrapper& rhs) 
    { 
    if (this != &rhs) 
    { 
     Block_release(this->block); 
     this->block = Block_copy(rhs.block); 
    } 
    return *this; 
    } 

    ~block_wrapper() 
    { 
    Block_release(this->block); 
    } 
}; 
0

recomiendo el uso de las versiones *_f de las funciones libdispatch. Todas las versiones de bloques se implementan en términos de las versiones de funciones bajo el capó, y es mucho más fácil escribir una plantilla de C++ que produce una función que llama un objeto lambda que una plantilla que produce un bloque que llama a un objeto lambda.

Sin embargo, la falta actual de soporte en Clang para C++ lambdas puede echar por tierra todo.

Cuestiones relacionadas