2012-06-12 8 views
8

Estoy comenzando a desarrollar aplicaciones usando C++ 11 lambdas, y necesito convertir algunos tipos a punteros a función. Esto funciona perfectamente en GCC 4.6.0:C++ 11 lambdas para el puntero de función

void (* test)() = []() 
{ 
    puts("Test!"); 
}; 

test(); 

Mi problema es cuando tengo que utilizar los métodos o funciones variables locales dentro de la lambda:

const char * text = "test!"; 

void (* test)() = [&]() 
{ 
    puts(text); 
}; 

test(); 

G ++ 4.6.0 da el código de error reparto:

main.cpp: In function 'void init(int)': 
main.cpp:10:2: error: cannot convert 'main(int argc, char ** argv)::<lambda()>' to 'void (*)()' in initialization 

Si el uso de automóviles , funciona bien:

const char * text = "Test!"; 

auto test = [&]() 
{ 
    puts(text); 
}; 

test(); 

Mi pregunta es: ¿cómo puedo crear un tipo de lambda con [&]? En mi caso, no puedo usar la STL std :: function (porque mi programa no utiliza el tiempo de ejecución de C++ RTTI y EXCEPTIONS), y ¿tiene una implementación de función simple para resolver este problema?

+8

Suena como una instancia del [problema XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). –

+3

No puede convertir una lambda de captura en un puntero de función. Explica lo que estás tratando de hacer. –

+0

Ha explicado (mal) un intento de solución, sin describir cuál es su problema real. Díganos cuál es su problema real – thecoshman

Respuesta

8

no puedo usar el std :: función STL (porque mi programa no utiliza C++ Tiempo de ejecución de RTTI y EXCEPCIONES)

Luego puede necesitar escribir su propio equivalente a std::function.

La implementación habitual del borrado de tipo para std::function no necesita RTTI para la mayoría de sus funcionalidades; funciona a través de llamadas a funciones virtuales regulares. Así que escribir tu propia versión es factible.

De hecho, las únicas cosas en std::function que necesitan RTTI son los target_type y target funciones, que no son las funciones más útiles del mundo. Es posible que solo pueda usar std::function sin llamar a estas funciones, suponiendo que la implementación que está utilizando no necesita RTTI para su negocio habitual.

Normalmente, cuando deshabilita el manejo de excepciones, el programa simplemente se apaga y se producen errores al encontrar una instrucción throw.Y como la mayoría de las excepciones que emitiría un std::function no son del tipo de cosas de las que podría recuperarse (llamar a un function vacío, quedarse sin memoria, etc.), probablemente solo pueda usar std::function como está.

8

Solo las lambdas sin captura se pueden convertir a un puntero de función. Esta es una extensión de lambdas solo para este caso particular [*]. En general, lambdas son objetos de función y no se puede convertir un objeto de función en una función.

La alternativa para lambdas que tienen estado (captura) es usar std::function en lugar de un puntero de función simple.


[*]: Si el lambda que mantiene el estado podría convertirse en función de puntero, donde se mantiene el estado? (Tenga en cuenta que puede haber varias instancias de este lambda particular, cada uno con su propio estado que necesita ser mantenido separado)

+0

Bueno, si lo pasa por un valor como este 'const int c; [c] (int i) -> int {return i * c;} 'tendría mucho sentido ... –

+0

@BarnabasSzabolcs: Depende, considere' std :: function f (int x) {const int c = x; return [c] (int i) {return i * c;}}; '. El funtor devuelto por 'f' depende de su argumento y, por lo tanto, tiene estado. Solo si la captura era una expresión constante, podría incluirse en una función simple. –

+0

Hm. Estoy de acuerdo, en parte. Todavía se puede quitar, pero la solución puede ser costosa, ya que el programa necesitaría copiar el código de la función lambda cada vez que cambie el valor de c en el código de la función. (o si no está copiando todo el código de la función, necesita hacer saltos planificados, donde los saltos pueden ralentizar las cosas.) –

6

Como se ha mencionado, solo las lambdas que no capturan nada se pueden convertir en indicadores de función.

Si no desea utilizar o escribir algo así como std :: function, entonces otra alternativa es pasar como parámetros las cosas que de otra manera capturaría. Incluso puedes crear una estructura para mantenerlos.

#include <iostream> 

struct captures { int x; }; 
int (*func)(captures *c) = [](captures *c){ return c->x; }; 

int main() { 
    captures c = {10}; 

    std::cout << func(&c) << '\n'; 
} 

Otra alternativa es utilizar thread_local/constexpr variables globales/estáticos/que no requieren la captura.

Cuestiones relacionadas