Estaba jugando con lambdas de C ++ y su conversión implícita a punteros de función. Mi ejemplo inicial fue usarlos como devolución de llamada para la función ftw. Esto funciona como se esperaba.
#include <ftw.h>
#include <iostream>
using namespace std;
int main()
{
auto callback = [](const char *fpath, const struct stat *sb,
int typeflag) -> int {
cout << fpath << endl;
return 0;
};
int ret = ftw("/etc", callback, 1);
return ret;
}
Después de modificarlo para usar capturas:
int main()
{
vector<string> entries;
auto callback = [&](const char *fpath, const struct stat *sb,
int typeflag) -> int {
entries.push_back(fpath);
return 0;
};
int ret = ftw("/etc", callback, 1);
for (auto entry : entries ) {
cout << entry << endl;
}
return ret;
}
Recibí el error del compilador:
error: cannot convert ‘main()::<lambda(const char*, const stat*, int)>’ to ‘__ftw_func_t {aka int (*)(const char*, const stat*, int)}’ for argument ‘2’ to ‘int ftw(const char*, __ftw_func_t, int)’
Después de leer un poco. Aprendí que las lambdas que usan capturas no se pueden convertir implícitamente en punteros de función.
¿Hay una solución para esto? ¿El hecho de que no se puedan convertir "implícitamente" significa que pueden convertirse "explícitamente"? (Intenté lanzar, sin éxito). ¿Cuál sería una forma limpia de modificar el ejemplo de trabajo para poder agregar las entradas a algún objeto usando lambdas?
c++
lambda
function-pointers
c++11
Duncan
fuente
fuente
void *
). Si la biblioteca que está utilizando permite este argumento adicional, encontrará una solución. De lo contrario, no tiene forma de lograr limpiamente lo que quiere hacer.Respuestas:
Dado que la captura de lambdas necesita preservar un estado, no existe realmente una "solución alternativa" simple, ya que no son solo funciones ordinarias. El punto sobre un puntero de función es que apunta a una única función global, y esta información no tiene espacio para un estado.
La solución alternativa más cercana (que esencialmente descarta el estado) es proporcionar algún tipo de variable global a la que se accede desde su función lambda /. Por ejemplo, podría crear un objeto functor tradicional y darle una función miembro estática que se refiere a alguna instancia única (global / estática).
Pero eso es como frustrar todo el propósito de capturar lambdas.
fuente
namespace
y las marcó comothread_local
, ese es elftw
enfoque que elegí para resolver algo similar.Me acabo de encontrar con este problema.
El código se compila bien sin capturas lambda, pero hay un error de conversión de tipo con captura lambda.
La solución con C ++ 11 es usar
std::function
(editar: se muestra otra solución que no requiere modificar la firma de la función después de este ejemplo). También puede usarboost::function
(que en realidad se ejecuta significativamente más rápido). Código de ejemplo: cambiado para que se compile, compilado congcc 4.7.1
:Editar: tuve que volver a visitar esto cuando me encontré con un código heredado en el que no podía modificar la firma de la función original, pero aún necesitaba usar lambdas. A continuación se muestra una solución que no requiere modificar la firma de la función original:
fuente
ftw
para tomar enstd::function
lugar de un puntero de función ...ftw
tuviera un argumento vacío * userdata, entonces preferiría la respuesta de @ evgeny-karpov.ORIGINAL
Las funciones Lambda son muy convenientes y reducen un código. En mi caso, necesitaba lambdas para programación paralela. Pero requiere punteros de captura y función. Mi solucion esta aqui. Pero tenga cuidado con el alcance de las variables que capturó.
Ejemplo
Ejemplo con valor de retorno
ACTUALIZAR
Versión mejorada
Ha pasado un tiempo desde que se publicó la primera publicación sobre lambda de C ++ con capturas como puntero de función. Como era utilizable para mí y para otras personas, hice algunas mejoras.
La API de puntero C de función estándar usa la convención void fn (void * data). De forma predeterminada, se usa esta convención y lambda debe declararse con un argumento void *.
Implementación mejorada
Ejemplo
Conversión de lambda con capturas a un puntero C
También se puede usar de esta manera
En caso de que se deba usar el valor de retorno
Y en caso de que se utilicen datos
fuente
Usando el método local global (estático) se puede hacer de la siguiente manera
Supongamos que tenemos
Entonces el uso será
Esto funciona porque cada lambda tiene una firma única, por lo que hacerla estática no es un problema. A continuación se muestra un contenedor genérico con un número variable de argumentos y cualquier tipo de retorno utilizando el mismo método.
Y uso similar
fuente
=
usar&i
en su bucle for.Jeje, una pregunta bastante antigua, pero aún así ...
fuente
Existe una forma hackear de convertir un lambda de captura en un puntero de función, pero debe tener cuidado al usarlo:
/codereview/79612/c-ifying-a-capturing-lambda
Su código se vería así (advertencia: compilación del cerebro):
fuente
Mi solución, solo use un puntero de función para referirse a una lambda estática.
fuente
Encontré una respuesta aquí: http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
Convierte
lambda pointer
avoid*
ida y vuelta converso cuando sea necesario.para
void*
:auto voidfunction = new decltype (to_function (lambda)) (to_function (lambda));
de
void*
:función automática = static_cast <std :: function *> (voidfunction);
fuente