我在玩C++ lambdas和它们到函数指针的隐式转换。我的开始例子是用它们作为ftw函数的回调。这和预期的一样工作。
#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)’
经过一些阅读,我了解到使用捕获的lambda不能隐式转换为函数指针。
有什么解决办法吗?它们不能被“隐式”转换的事实是否意味着它们可以被“显式”转换?(我尝试过强制转换,但没有成功)。有什么干净的方法可以修改工作示例,以便我可以使用lambda将条目附加到某个对象?
9条答案
按热度按时间3zwjbxry1#
我刚碰到这个问题。
如果没有lambda捕获,代码可以很好地编译,但是使用lambda捕获时会出现类型转换错误。
C++11的解决方案是使用
std::function
(编辑:另一个不需要修改函数签名的解决方案显示在这个例子之后)。你也可以使用boost::function
(它实际上运行速度快得多)。示例代码-修改后可以编译,用gcc 4.7.1
编译:编辑:当我遇到遗留代码时,我不得不重新考虑这个问题,因为我不能修改原始函数的签名,但仍然需要使用lambdas。下面是一个不需要修改原始函数签名的解决方案:
lb3vh1jj2#
因为捕获lambda需要保留一个状态,所以实际上没有一个简单的“变通方法”,因为它们 * 不 * 只是普通的函数。函数指针的要点在于它指向一个单独的全局函数,而这个信息没有给状态留空间。
最接近的解决方案(本质上放弃了状态性)是提供某种类型的全局变量,它可以从lambda/函数访问。例如,可以创建一个传统的functor对象,并给予它一个静态成员函数,它引用某个唯一的(全局/静态)示例。
但这有点违背了捕捉拉姆达的全部目的。
hgc7kmma3#
Lambda函数非常方便并且减少了代码。在我的例子中,我需要Lambda来进行并行编程。但是它需要捕获和函数指针。我的解决方案在这里。但是要注意你捕获的变量的范围。
示例
具有返回值的示例
改进版本
自从第一篇关于C++ lambda函数指针的文章发表以来已经有一段时间了,因为它对我和其他人都有用,我做了一些改进。
标准函数C指针api使用void fn(void * data)约定。默认情况下使用此约定,并且lambda应该使用void * 参数声明。
改进执行情况
埃萨姆莱
将带有捕获的lambda转换为C指针
也可以这样使用
如果应使用返回值
如果数据被用来
lqfhib0f4#
使用局部全局(静态)方法,可以按如下方式完成
假设我们有
所以用法是
这样做是因为每个lambda都有一个唯一的签名,所以使它成为静态不是问题。下面是一个泛型 Package 器,它有可变数量的参数和使用相同方法的任何返回类型。
以及类似的用法
jvidinwx5#
呵呵,这是个老问题了,不过还是......
cqoc49vn6#
我的解决方案是,只使用函数指针来引用静态lambda。
zphenhs47#
有一种方法可以将捕获lambda转换为函数指针,但在使用时需要小心:
https://codereview.stackexchange.com/questions/79612/c-ifying-a-capturing-lambda
代码将如下所示(警告:大脑编译):
aemubtdh8#
@vladimir-talybin制作的answer有一个小问题:
也就是说,如果lambda在函数中被调用了两次,那么只有第一次调用是有效的。
您将显示
2
和0
的输出,这意味着call
函数的第二次调用正在使用第一次调用的lambda闭包。这是因为这个解决方案使用static来存储闭包的引用,一旦引用被存储,它就不会被改变,即使是一个新的闭包。如果闭包被析构(由于超出作用域或其他原因),情况会变得更糟。
我对这个问题的解决方案是简单地将引用转换为指针,并在每次“构造”lambda时更新指针的值:
开销是多两次内存访问,一次用于读,一次用于写,但是确保了正确性。
zvokhttg9#
在这里找到了答案:http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html
它将
lambda pointer
转换为void*
,并在需要时转换回来。1.至
void*
:自动无效函数=新decltype(目标函数(λ))(目标函数(λ));
1.从
void*
开始:auto函数= static_cast〈标准::函数 *〉(无效函数);