從最簡單的情況說起
煤捕捉任何狀態的lambda可以直接轉化成普通的C function型態
1 2 3 4 5 6 7 8
| typedef void(*callback)(); void testFunc(callback cb) { cb(); } testFunc([] { cout << "Lambda function" << endl; });
|
帶狀態的情形
通常callback還會帶一個void *參數,可以讓你上下其手
1 2 3 4 5 6 7 8 9 10
| typedef void(*callback)(void *); void testFunc(callback cb, void *user_data) { cb(user_data); } int v = 123; testFunc([](void *user_data) { int *v = static_cast<int *>(user_data); cout << "Lambda function " << *v<< endl; }, &v);
|
當需要更多上下文時,需要自行定義structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| int x = 0; float y = 1;
struct MtEverest { MtEverest() = default; MtEverest(const MtEverest& that) = delete; MtEverest(const MtEverest&& that) = delete; } mt_everest;
auto payload = std::tie(x, y, mt_everest); testFunc([](void *user_data) { auto& payload_tup = *reinterpret_cast<decltype(payload)*>(user_data); auto& xx = std::get<0>(payload_tup); auto& yy = std::get<1>(payload_tup); auto& me = std::get<2>(payload_tup); }, &payload);
|
更高明的解法
當C API沒辦法有void *的指標讓你上下其手,或是packing/unpacking的程式碼讓人不耐
可以考慮以下這個解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| template <typename Lambda> static auto lambdacb(Lambda &&l) { thread_local auto* p = &l; p = &l; return []() { return (*p)(); }; }
typedef void(*callback)(); void testFunc(callback cb) { cb(); }
int x = 0; float y = 1;
testFunc(lambdacb([&x, &y] { cout << x << " " << y << endl; }));
|
Reference
— Lambda Magic
— Lambda Callbacks
— Technical Debt