捕获的C ++ lambda作为函数指针
我正在玩C ++ lambda和他们隐式转换为函数指针。 我的起始示例是使用它们作为ftw函数的callback函数。 这按预期工作。
#include <ftw.h> #include <iostream> using namespace std; int main() { auto callback = [](const char *fpath, const struct stat *sb, int typeflag) -> int { cout << fpath << endl; return 0; }; int ret = ftw("/etc", callback, 1); return ret; }
修改后使用捕获:
int main() { vector<string> entries; auto callback = [&](const char *fpath, const struct stat *sb, int typeflag) -> int { entries.push_back(fpath); return 0; }; int ret = ftw("/etc", callback, 1); for (auto entry : entries ) { cout << entry << endl; } return ret; }
我得到了编译器错误:
error: cannot convert 'main()::<lambda(const char*, const stat*, int)>' to '__ftw_func_t {aka int (*)(const char*, const stat*, int)}' for argument '2' to 'int ftw(const char*, __ftw_func_t, int)'
经过一番阅读。 我了解到,使用捕获的lambdaexpression式不能隐式转换为函数指针。
有没有解决方法? 他们不能被“隐式”转换的事实意味着他们可以“明确”地转换吗? (我试图铸造,没有成功)。 什么将是一个干净的方式来修改工作的例子,以便我可以附加条目使用lambdas的一些对象?
由于捕获lambda需要保存一个状态,所以并不是一个简单的“解决方法”,因为它们不仅仅是普通的函数。 关于函数指针的一点是它指向一个单一的全局函数,而这个信息没有空间存放一个状态。
最接近的解决方法(基本上放弃了有状态)是提供某种types的全局variables,可以从您的lambda /函数访问。 例如,您可以创build一个传统的函子对象,并为其提供一个静态成员函数,该函数引用某个唯一(全局/静态)实例。
但是这就是击败捕捉lambdas的全部目的。
我刚碰到这个问题。
代码编译没有lambda捕获罚款,但有一个lambda捕获types转换错误。
C ++ 11的解决scheme是使用std::function
。 你也可以使用boost::function
(实际运行速度明显更快)。 示例代码 – 更改以便编译,使用gcc 4.7.1
编译:
#include <iostream> #include <vector> #include <functional> using namespace std; int ftw(const char *fpath, std::function<int (const char *path)> callback) { return callback(fpath); } int main() { vector<string> entries; std::function<int (const char *fpath)> callback = [&](const char *fpath) -> int { entries.push_back(fpath); return 0; }; int ret = ftw("/etc", callback); for (auto entry : entries ) { cout << entry << endl; } return ret; }
Lambda函数非常方便,减less了代码。 在我的情况下,我需要lambdas并行编程。 但是它需要捕获和函数指针。 我的解决scheme在这里。 但要小心你捕获的variables的范围。
template<typename Tret, typename T> Tret lambda_ptr_exec(T* v) { return (Tret) (*v)(); } template<typename Tret = void, typename Tfp = Tret(*)(void*), typename T> Tfp lambda_ptr(T& v) { return (Tfp) lambda_ptr_exec<Tret, T>; }
例
int a = 100; auto b = [&]() { a += 1;}; void (*fp)(void*) = lambda_ptr(b); fp(&b);
带返回值的示例
int a = 100; auto b = [&]() {return a;}; int (*fp)(void*) = lambda_ptr<int>(b); fp(&b);
呵呵 – 这是一个很老的问题,但是…
#include <iostream> #include <vector> #include <functional> using namespace std; // We dont try to outsmart the compiler... template<typename T> int ftw(const char *fpath, T callback) { return callback(fpath); } int main() { vector<string> entries; // ... now the @ftw can accept lambda int ret = ftw("/etc", [&](const char *fpath) -> int { entries.push_back(fpath); return 0; }); // ... and function object too struct _ { static int lambda(vector<string>& entries, const char* fpath) { entries.push_back(fpath); return 0; } }; ret = ftw("/tmp", bind(_::lambda, ref(entries), placeholders::_1)); for (auto entry : entries ) { cout << entry << endl; } return ret; }
将捕获的lambda转换为函数指针是一种诡异的方式,但是在使用时需要小心:
https://codereview.stackexchange.com/questions/79612/c-ifying-a-capturing-lambda
你的代码看起来像这样(警告:大脑编译):
int main() { vector<string> entries; auto const callback = cify<int(*)(const char *, const struct stat*, int)>([&](const char *fpath, const struct stat *sb, int typeflag) -> int { entries.push_back(fpath); return 0; }); int ret = ftw("/etc", callback, 1); for (auto entry : entries ) { cout << entry << endl; } return ret; }
我在Visual Studio 2010中遇到了类似的问题,并且find了解决方法 。 我不确定它是否能够与捕捉工作,因为我没有testing过这种情况,但我不明白为什么它不会。
让我知道如果它不起作用,我会看看我是否可以修复它。
在这里find答案: http : //meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
它将lambda pointer
转换为void*
并在需要时转换回来。
-
void*
:auto voidfunction = new decltype(to_function(lambda))(to_function(lambda));
-
来自
void*
:auto function = static_cast <std :: function *>(voidfunction);