目前我使用以下代码将捕获 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 参数类型中推导出模板参数?
这可以通过检查
&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 {
// ...
}
)
但请注意评论中提出的问题