2011-08-26 7 views
6

今私はC++ 11で遊んでいますが、ラムダをsqliteのコールバックとして使用する場合、次の問題があります。ラムダ内のベクトル変数をキャプチャすると、署名が一致しないというエラーが表示されます。ラムダ([]の変数を[&ret]の代わりに使用し、retを使用しない場合)は、正常に動作します。キャプチャされた変数あり/なしのラムダ間のシグネチャの違い?

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のバージョンは、 "GCC(XvidVideo.RU - GCC 4.6.1はi686-PC-MINGW32)4.6.1 20110625(プレリリース)" である上Windows。

なぜこれが違いますか?

+0

これはVS2010のIMPLにおける既知のバグであれば誰もが知っています...私は、Visual Studio 2010のコンパイラで同じことをしようとしているし、それはラムダの形態のいずれかを好きではありませんか? –

答えて

6

キャプチャレスラムダのみが関数へのポインタに変換され、コンパイラの診断に基づいて、sqlite3_execはそのようなポインタint (*)(void*, int, char**, char**)を想定しています。無ラムダキャプチャとラムダ発現のため閉鎖型公共非仮想非明示的なconstの変換機能を有している5.1.2 [expr.prim.lambda]/6

を引用する

クロージャ型の関数呼び出し演算子と同じパラメータと戻り値の型を持つ関数へのポインタへのポインタ。

+0

意味があります。キャプチャされた変数でこれをどのようにでも解決できるかどうかを知りたかっただけです。 (この特別なケースでは、もちろん私の目的のためにsqliteのコールバック変数を使うことができます。) – AndiDog

+0

@AndiDog Cライブラリのために非常に多くのC++コールバックのやり方をとらなければならないと思います。いくつかの 'void * 'に基づいて本当に呼び出すべきものを見つけ出します。 – Cubbi

+2

はい、 'sqlite3_exec'はコールバックに' void * 'を渡すことができますが、C++ 11ではこれが簡単にできると思っていました。 – AndiDog

1

コールバックには第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);