11

在 C++11 中,如何声明一个将 lambda 表达式作为参数的函数?我可以在网上找到大量用于声明 lambda 或将它们作为模板参数的资源,但我真正想做的是能够将 lambda 用作易于声明的回调处理程序,类似于通过闭包实现的功能在 JavaScript 和 Objective-C 中的代码块中。

本质上,我想用 lambda 替换的经典 C++ 构造类似于:

class MyCallback {
public:
    virtual ~MyCallback() {}
    virtual void operator(int arg) = 0;
};

void registerCallback(const std::shared_ptr<MyCallback> &);

void foo(void) {
    int a, b, c;
    class LocalCallback: public MyCallback {
        int a, b, c;
    public:
        LocalCallback(int a, int b, int c): a(a), b(b), c(c) {}
        void operator(int arg) { std::cout << (a+b+c)*arg << std::endl; }
    };
    registerCallback(std::shared_ptr<MyCallback>(new LocalCallback(a,b,c)));
}

这将被简化为:

void registerCallback(/* WHAT GOES HERE? */);

void foo(void) {
    int a, b, c;
    registerCallback([=](int arg){std::cout << (a+b+c)*arg << std::endl; })
}

那么,我写了/* WHAT GOES HERE? */什么?

编辑:这是为了存储回调以便稍后回调,而不是立即使用和调用它。

4

3 回答 3

19

通常const std::function<void(int)> &std::function<void(int)>

我不确定是否std::function应该通过 const 引用或值传递的判断是什么。可能按价值计算是可以的,特别是因为无论如何你都要复制它来存储。

如果在所有语法中间不清楚,它void(int)是一个函数类型,std::function<T>大致意思是“一个与 T 类型的函数具有相同签名的函子”。

Lambda 本身具有匿名类型。没有办法命名你的 lambda 表达式的类型,并且具有相同签名的不同 lambda 表达式的类型是不同的:

auto foo = [=](int arg){std::cout << (a+b+c)*arg << std::endl; };
auto bar = [=](int arg){std::cout << (a+b+c)*arg << std::endl; };
// foo and bar have different types, accessible as decltype(foo), decltype(bar)

因此需要std::function,它基本上是一个类型擦除包装器,用于将具有相同签名的不同仿函数聚集到一个通用类型中。它是带有模板的静态多态性与您需要的动态多态性之间的桥梁,如果您想注册一个回调,将其存储以备后用,然后在不“记住”原始类型的情况下调用它。

于 2012-05-23T20:18:24.070 回答
7
void registerCallback(const std::function<void(int)>& callback);
于 2012-05-23T20:16:33.753 回答
5

考虑使用函数模板。有很多很好的理由,例如重载时的更好行为(重载std::function是痛苦的):

template<typename Functor>
void registerCallback(Functor&& functor);

(您也可以接受参数为Functor functor,这不是太重要。)

如果代码需要functor稍后存储,那么它可能会保存在std::function. 您要避免的地方std::function是函数参数。

于 2012-05-23T21:31:04.030 回答