c++ - closure - lambda auto



捕获的C++ lambda作为函数指针 (5)

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>;
}

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);

https://src-bin.com

我正在玩C ++ lambda和它们隐式转换为函数指针。 我的开始的例子是使用它们作为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表达式不能隐式转换为函数指针。

有没有解决方法? 他们不能“隐式”转换的事实意味着他们可以“明确”转换吗? (我尝试投射,但没有成功)。 什么将是一个干净的方式来修改工作示例,以便我可以使用lambdas将条目追加到某个对象?


Answer #1

使用本地全局(静态)方法可以按照以下方式完成

template <class T>
auto wrap(T t) {
  static T fn = t;
  return [] { fn(); };
}

假设我们有

void some_c_func(void (*callback)());

所以用法是

some_c_func(wrap([&] {
  // code
}));

这是有效的,因为每个lambda都有一个独特的签名,因此使其成为静态不是问题。 使用可变参数个数的泛型包装和任何使用相同方法的返回类型。

template <class T>
struct lambda_traits : lambda_traits<decltype(&T::operator())>
{ };

template <class T, class R, class... Args>
struct lambda_traits<R(T::*)(Args...) const> {
    typedef R (*pointer)(Args...);

    static pointer cify(T t) {
        static T fn = t;
        return [](Args... args) {
            return fn(args...);
        };
    }
};

template <class T>
inline typename lambda_traits<T>::pointer cify(T t) {
    return lambda_traits<T>::cify(t);
}

和类似的用法

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;
}));


Answer #3

将捕获的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;
}

Answer #4

由于捕获lambda需要保存一个状态,因此它不是一个简单的“解决方法”,因为它们不仅仅是普通的函数。 关于函数指针的一点是它指向一个单一的全局函数,并且这个信息没有空间存放状态。

最接近的解决方法(基本上放弃了有状态)是提供某种类型的全局变量,它可以从您的lambda /函数访问。 例如,您可以创建一个传统的函数对象,并为其提供一个静态成员函数,该函数引用一些独特的(全局/静态)实例。

但是这有点击败了捕获lambda的全部目的。





c++11