scratch lapiz control bloques bloque c++ c++11 lambda clang

c++ - control - bloque de lapiz en scratch



¿Es posible convertir un C++ 0x lambda en un bloque de sonido? (5)

Me he preguntado si es posible convertir un C ++ 0x lambda en un bloque de sonido. Hasta ahora, todo lo que he visto en él ha involucrado la discusión entre sus diferencias. Mi principal razón para analizar esto es hacer un envoltorio eventual para libdispatch , y aunque estoy bastante al tanto de las funciones de dispatch_*_f libdispatch , ha faltado bastante información sobre su uso, en comparación con su contraparte de bloque.

Hasta ahora he podido encontrar información sobre cómo convertir un lambda de C ++ en un puntero de función , pero esto es más en el ámbito de lo contrario.

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


Bueno, Clang aún no admite lambdas, y tampoco lo hace el GCC de Apple. Los FSC GCC lo suficientemente recientes para soportar las lambdas no admiten los bloques AFAIK. Así que la cuestión de la conversión entre ellos todavía no se aplica.

Una vez que Clang admita ambos, puede haber una manera en el modo ObjC ++ para convertir entre ellos.


En general, cuando se utiliza lambda para el cierre "hacia abajo", puede convertir un lambda c ++ en un bloque de sonido convirtiendo:

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

a:

^(int i) { return i; }

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

Finalmente, si se necesita un cierre "hacia arriba", entonces los dos divergen drásticamente. Los bloques de Clang requieren que las variables capturadas se __block con __block , que el compilador las asignará en el montón. Considerando que, en C ++, la forma en que se captura la lambda, debe decidirse en función de la vida útil del objeto (esto es, por valor, hacer una copia o por referencia).

También en C ++, la copia del cierre se maneja automáticamente mediante el mecanismo constructor de copia en C ++. Sin embargo, con el bloque de Block_copy , se debe llamar a Block_copy y Block_release para manejar la copia del bloque. Se puede escribir una envoltura 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); } };


No creo que un verdadero converso sea posible. A diferencia del caso inverso, deshacerse del bloque de sonido original, tiene algunos efectos secundarios de los que no puedes recuperarte. Si bien 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 intente usar la lambda. Por otro lado, los bloques pueden interactuar con las variables declaradas con el __block almacenamiento __block , en cuyo caso estas variables se mantendrán en la memoria (incluso si esto significa que se copien de una pila a otra) mientras el bloque __block (incluidas las copias realizadas). por Block_copy ):

Las variables __block viven en el almacenamiento que se comparte entre el ámbito léxico de la variable y todos los bloques y copias de bloque declaradas o creadas dentro del ámbito léxico de la variable. Por lo tanto, el almacenamiento sobrevivirá a la destrucción del marco de la pila si alguna de las copias de los bloques declarados dentro del marco sobrevive más allá del final del marco (por ejemplo, al ser en cola en algún lugar para su posterior ejecución).

Por lo tanto, a menos que intente mantener el bloque original (y, por lo tanto, envolverlo en lugar de convertirlo), faltará algo de su funcionalidad original, ya que las variables __block desaparecerán.

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


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

Sin embargo, la actual falta de soporte en Clang para las lambdas de C ++ puede afectar a todo esto.


Se acaba de agregar un parche que habilita esta conversión implícitamente a clang trunk.