2011-08-26 6 views
6

Estoy jugando con C++ 11 en este momento y encontré el siguiente problema con el uso de una lambda como devolución de llamada a sqlite. Al capturar una variable vectorial dentro de la lambda, aparece un error que dice que las firmas no coinciden. Sin usar esa variable en el lambda ([] en lugar de [&ret], y no usando ret dentro), funciona bien.¿Diferencia de firma entre lambda con/sin variable capturada?

vector<SomeClass> ret; 
char *err = nullptr; 
int res = sqlite3_exec(db, 
         "some sql query, doesn't matter", 
         [&ret](void *unused, int argc, char **argv, char **columnName) -> int 
         { 
          ret.push_back(SomeClass()); 
          return 0; 
         }, 
         nullptr, 
         &err); 

Este es el error que consigo:

cannot convert 'TestClass::testMethod()::<lambda(void*, int, char**, char**)>' to 'int (*)(void*, int, char**, char**)' for argument '3' to 'int sqlite3_exec(sqlite3*, const char*, int (*)(void*, int, char**, char**), void*, char**)' 

versión de GCC es "gcc (XvidVideo.RU - GCC 4.6.1 i686-pc-mingw32) 4.6.1 20110625 (preliminar)" en la Windows.

¿Por qué esto hace la diferencia?

+0

Estoy intentando lo mismo con el Visual Studio 2010 y el compilador no le gusta cualquiera de las formas de la lambda ... ¿Alguien sabe si esto es un error conocido en el VS2010 impl? –

Respuesta

6

Solo las lambdas sin capturas se pueden convertir en punteros para funcionar y, según el diagnóstico del compilador, su sqlite3_exec espera un puntero, int (*)(void*, int, char**, char**).

Para citar §5.1.2 [expr.prim.lambda]/6

El tipo de cierre para un lambda-expresión sin lambda de captura tiene una función de conversión public const no virtual no explícita al puntero a la función que tiene el mismo parámetro y tipos de retorno que el operador de llamada de función del tipo de cierre.

+0

Tiene sentido. Solo quería saber si puedo resolver esto con las variables capturadas de cualquier manera. (En este caso especial, por supuesto, puedo usar la variable de devolución de llamada de sqlite para mis propósitos.) – AndiDog

+0

@AndiDog Supongo que tendrías que ir por el camino de tantas devoluciones de llamada de C++ para bibliotecas C: una función miembro no miembro o estática que se da cuenta de lo que realmente se llama basado en algún 'void *'. – Cubbi

+2

Sí, 'sqlite3_exec' me permite pasar un' void * 'a la devolución de llamada, ingenuamente pensé que esto podría hacerse más fácilmente con C++ 11. – AndiDog

1

¿qué ocurre con el uso del primer argumento para la devolución de llamada?

vector<SomeClass> ret; 
char *err = nullptr; 
int res = sqlite3_exec(db, 
         "some sql query, doesn't matter", 
         [](void *ctx, int argc, char **argv, char **columnName) -> int 
         { 
          static_cast<vector<SomeClass>*>(ctx)->push_back(SomeClass()); 
          return 0; 
         }, 
         &ret, 
         &err); 
Cuestiones relacionadas