2011-08-26 38 views
6

我现在正在玩C++ 11,发现使用lambda作为sqlite回调的问题如下。当在lambda内部捕获一个向量变量时,我得到一个错误,说明签名不匹配。如果不在lambda中使用该变量([]而不是[&ret],而不是在里面使用ret),它可以正常工作。带/不带捕获变量的lambda之间的签名区别?

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); 

这是错误我得到:

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**)' 

GCC版本是 “海湾合作委员会(XvidVideo.RU - GCC 4.6.1的i686-PC-的mingw32)4.6.1 20110625(抢鲜)” 上视窗。

为什么这会有所作为?

+0

我想与Visual Studio 2010编译器一样的东西,它不喜欢任何形式的lambda ...有谁知道这是否是VS2010中的已知错误impl? –

回答

6

只有无捕获的lambdas可以转换为函数指针,并且基于编译器诊断,您的sqlite3_exec需要这样一个指针,int (*)(void*, int, char**, char**)

引述§5.1.2[expr.prim.lambda]/6

对于没有λ-捕获的λ-表达的闭合类型有一个公共的非虚拟非显式const的转换函数指向具有与闭包类型的函数调用操作符相同的参数和返回类型的函数。

+0

有道理。只是想知道我是否可以用任何方式解决这个捕获的变量。 (在这种特殊情况下,我当然可以使用sqlite的回调变量用于我的目的。) – AndiDog

+0

@AndiDog我猜你必须为C库带来如此多的C++回调:非成员或静态成员函数根据一些'void *'指出真正要调用的内容。 – Cubbi

+2

是的,'sqlite3_exec'允许我将'void *'传递给回调函数,我只是天真地认为用C++ 11可以做到这一点。 – AndiDog

1

如何使用回调的第一个参数?

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);