【问题标题】:C++ lambda callbacksC++ lambda 回调
【发布时间】:2020-06-23 12:39:09
【问题描述】:

我正在尝试创建一个 HTTP 类,并且我想通过 lambda 使用 C++11(还不是 C++14)回调。我有 2 个模型可用,第一个可以工作……但看起来很难看。我瞄准的第二个不是编译(最后出错)。

我不能使用std::function,因为这是一个嵌入式项目,并且该模板会生成大量代码。

#include <cstring>

class HTTP
{
public:
    void get1(const char* url, void* context, void (*callback)(void*, const char*) )
    {
        callback(context, "");
    }

    void get2(const char* url, void (*callback)(const char*) )
    {
        callback("");
    }
};

void test()
{
    int k;
    HTTP http;
    http.get1( "http://google.com", &k, [](void* context, const char* s){
        int *k = (int*) context;
        *k = strlen(s);
    });

    // this does not compile, looking for other alternatives
    http.get2( "http://google.com", [&k](const char* s){
        k = strlen(s);
    });
}

来自 gcc 的错误(xtensa-esp32-elf-g++ (crosstool-NG crosstool-ng-1.22.0-80-g6c4433a) 5.2.0)

HttpRequests.cpp: In function 'void test()':
HttpRequests.cpp:29:6: error: no matching function for call to 'HTTP::get2(const char [18], test()::<lambda(const char*)>)'
     });
      ^
HttpRequests.cpp:11:10: note: candidate: void HTTP::get2(const char*, void (*)(const char*))
     void get2(const char* url, void (*callback)(const char*) )
          ^
HttpRequests.cpp:11:10: note:   no known conversion for argument 2 from 'test()::<lambda(const char*)>' to 'void (*)(const char*)'

【问题讨论】:

  • 为什么不将get2 设为可以接受任何可调用对象的函数模板呢? :template&lt;class F&gt; void get2(const char* url, F f) { f(""); }.

标签: c++11 lambda callback gcc5.2


【解决方案1】:

没有捕获列表的 Lambda 与函数指针兼容,因此您的第一个 lambda 可以作为参数传递给 get1()。但是,带有捕获列表的 lambda 不能转换为函数指针,因此不能将其传递给 get2()

带有捕获的 Lambda 有状态,但函数不能有状态,这就是此类 lambda 不能转换为函数指针的原因。

让函数接受任何 lambda(或任何可调用对象)的最常见方法是使用函数模板:

class HTTP {

    // ...

    template <typename Callable>
    void get1(const char* url, void* context, Callable callback)
    {
        callback(context, "");
    }

    template <typename Callable>
    void get2(const char* url, Callable callback)
    {
        callback("");
    }
}

作为函数模板,代码大小可能会成为一个问题。如果这不可接受,请保留您当前的函数并限制自己从不传递使用捕获的 lambda。

【讨论】:

  • 很好.. 但是,我如何通知 API 用户需要使用的参数?有了这个(工作)实现,他的工作就是猜测我需要什么。
  • @elcuco C++20 概念可能会有所帮助,但我想这太新了,不能成为您的选择。因此,您只需记录预期的签名即可。
猜你喜欢
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 2012-09-20
  • 2014-10-20
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
相关资源
最近更新 更多