将 C++ 捕获 lambda 转换为函数指针,通用方法

问题描述 投票:0回答:1

目前我使用以下代码将捕获 lambda 转换为 C 风格 API 的函数指针:

template <typename... T, typename Callable>
auto wrap_closure(const Callable& c) -> void(*)(T...)
{
    static Callable closure = std::move(c);
    return +[](T... data) {
        closure(data...);
    };
}

它可以像这样使用:

  // we have EthernetClient& client reference captured by lambda
  void* s = mz_stream_write_callback_create(
    wrap_closure<const void*, int32_t>(
      [&](const void* buf, int32_t size) -> void {
        while(size > 0) {
          // we're writing without compression, so I expect the file data to come in chunks of HTTP_req array size
          // because this is how we read'em in line 221
          size_t written = client.write((const uint8_t*)buf, std::min(size_t(size), sizeof(HTTP_req)));
          if(!written) {
            break;
          }
          size -= written;
          buf = (const uint8_t*)buf + written;
        }
      }
    )
  );

唯一的缺点是我必须输入参数类型两次 - 首先在模板参数中,然后在 lambda 本身中。是否可以从 lambda 参数类型中推导出模板参数?

c++ templates lambda
1个回答
0
投票

这可以通过检查

&Closure::operator()
的类型来完成。你可以借鉴
std::function
现有的演绎指南
:

template <typename Callable>
auto wrap_closure(const Callable& c)
{
    static Callable closure = std::move(c);

    return []<typename Ret, typename... T>(std::function<Ret(T...)>*) {
        return +[](T... data) -> Ret {
            return closure(data...);
        };
    }(static_cast<decltype(std::function(closure))*>(nullptr));
}

您也可以仅在模板参数中命名类型并使用通用 lambda:

wrap_closure<const void*, int32_t>(
    [&](auto buf, auto size) -> void {
        // ...
    }
)

但请注意评论中提出的问题

© www.soinside.com 2019 - 2024. All rights reserved.