dun*_*can 83 c++ lambda function-pointers c++11
我正在玩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;
}
Run Code Online (Sandbox Code Playgroud)
修改后使用捕获:
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;
}
Run Code Online (Sandbox Code Playgroud)
我收到了编译器错误:
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)’
Run Code Online (Sandbox Code Playgroud)
经过一番阅读.我了解到使用捕获的lambda 无法隐式转换为函数指针.
这有解决方法吗?它们不能"隐式"转换的事实是否意味着它们可以"明确地"转换?(我试过铸造,没有成功).什么是修改工作示例的简洁方法,以便我可以使用lambdas将条目附加到某个对象?
Jay*_*est 46
我刚遇到这个问题.
代码在没有lambda捕获的情况下编译良好,但是lambda捕获存在类型转换错误.
使用C++ 11的解决方案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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:当我遇到遗留代码时,我不得不重新审视这一点,我无法修改原始函数签名,但仍然需要使用lambdas.不需要修改原始函数的函数签名的解决方案如下:
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
// Original ftw function taking raw function pointer that cannot be modified
int ftw(const char *fpath, int(*callback)(const char *path)) {
return callback(fpath);
}
static std::function<int(const char*path)> ftw_callback_function;
static int ftw_callback_helper(const char *path) {
return ftw_callback_function(path);
}
// ftw overload accepting lambda function
static int ftw(const char *fpath, std::function<int(const char *path)> callback) {
ftw_callback_function = callback;
return ftw(fpath, ftw_callback_helper);
}
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;
}
Run Code Online (Sandbox Code Playgroud)
Ker*_* SB 40
由于捕获lambda表达式需要保存的状态,确实没有一个简单的"解决方法",因为它们不只是普通的功能.关于函数指针的观点是它指向单个全局函数,并且该信息没有状态空间.
最接近的解决方法(基本上丢弃有状态)是提供从lambda /函数访问的某种类型的全局变量.例如,您可以创建一个传统的functor对象,并为其提供一个静态成员函数,该函数引用一些唯一的(全局/静态)实例.
但这有点击败了捕捉lambdas的整个目的.
Evg*_*pov 11
原版的
Lambda函数非常方便并减少代码.在我的情况下,我需要lambdas进行并行编程.但它需要捕获和函数指针.我的解决方案在这里.但要小心你捕获的变量范围.
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>;
}
Run Code Online (Sandbox Code Playgroud)
例
int a = 100;
auto b = [&]() { a += 1;};
void (*fp)(void*) = lambda_ptr(b);
fp(&b);
Run Code Online (Sandbox Code Playgroud)
带返回值的示例
int a = 100;
auto b = [&]() {return a;};
int (*fp)(void*) = lambda_ptr<int>(b);
fp(&b);
Run Code Online (Sandbox Code Playgroud)
UPDATE
改良版
自从第一篇关于C++ lambda的帖子发布以来,已经有一段时间了.因为它对我和其他人有用,所以我做了一些改进.
标准函数C指针api使用void fn(void*data)约定.默认使用此约定,并且应使用void*参数声明lambda.
改进实施
struct Lambda {
template<typename Tret, typename T>
static Tret lambda_ptr_exec(void* data) {
return (Tret) (*(T*)fn<T>())(data);
}
template<typename Tret = void, typename Tfp = Tret(*)(void*), typename T>
static Tfp ptr(T& t) {
fn<T>(&t);
return (Tfp) lambda_ptr_exec<Tret, T>;
}
template<typename T>
static void* fn(void* new_fn = nullptr) {
static void* fn;
if (new_fn != nullptr)
fn = new_fn;
return fn;
}
};
Run Code Online (Sandbox Code Playgroud)
Exapmle
int a = 100;
auto b = [&](void*) {return ++a;};
Run Code Online (Sandbox Code Playgroud)
将带有捕获的lambda转换为C指针
void (*f1)(void*) = Lambda::ptr(b);
f1(nullptr);
printf("%d\n", a); // 101
Run Code Online (Sandbox Code Playgroud)
也可以这种方式使用
auto f2 = Lambda::ptr(b);
f2(nullptr);
printf("%d\n", a); // 102
Run Code Online (Sandbox Code Playgroud)
如果应该使用返回值
int (*f3)(void*) = Lambda::ptr<int>(b);
printf("%d\n", f3(nullptr)); // 103
Run Code Online (Sandbox Code Playgroud)
如果使用数据
auto b2 = [&](void* data) {return *(int*)(data) + a;};
int (*f4)(void*) = Lambda::ptr<int>(b2);
int data = 5;
printf("%d\n", f4(&data)); // 108
Run Code Online (Sandbox Code Playgroud)
使用局部全局(静态)方法,可以按照以下方式完成
template <class F>
auto cify_no_args(F&& f) {
static F fn = std::forward<F>(f);
return [] {
return fn();
};
}
Run Code Online (Sandbox Code Playgroud)
假设我们有
void some_c_func(void (*callback)());
Run Code Online (Sandbox Code Playgroud)
所以用法将是
some_c_func(cify_no_args([&] {
// code
}));
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为每个lambda都有一个唯一的签名,所以使它静态不是问题.使用具有可变参数数量的通用包装器和使用相同方法的任何返回类型.
template <class F>
struct lambda_traits : lambda_traits<decltype(&F::operator())>
{ };
template <typename F, typename R, typename... Args>
struct lambda_traits<R(F::*)(Args...)> : lambda_traits<R(F::*)(Args...) const>
{ };
template <class F, class R, class... Args>
struct lambda_traits<R(F::*)(Args...) const> {
using pointer = typename std::add_pointer<R(Args...)>::type;
static pointer cify(F&& f) {
static F fn = std::forward<F>(f);
return [](Args... args) {
return fn(std::forward<Args>(args)...);
};
}
};
template <class F>
inline lambda_traits<F>::pointer cify(F&& f) {
return lambda_traits<F>::cify(std::forward<F>(f));
}
Run Code Online (Sandbox Code Playgroud)
和类似的用法
void some_c_func(int (*callback)(some_struct*, float));
some_c_func(cify([&](some_struct* s, float f) {
// making use of "s" and "f"
return 0;
}));
Run Code Online (Sandbox Code Playgroud)
小智 5
呵呵 - 一个很老的问题,但仍然......
#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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
46132 次 |
| 最近记录: |