嵌入传递 lambda 函数作为回调参数

Posted

技术标签:

【中文标题】嵌入传递 lambda 函数作为回调参数【英文标题】:Embind pass lambda function as callback parameter 【发布时间】:2016-04-02 08:49:46 【问题描述】:

我想创建一个函数来计算一些东西。并在完成后调用回调函数。

void calculate(int param1, ..., std::function<void(void)> callback) 
    //code...
    callback();

函数的绑定是使用Embind创建的:

EMSCRIPTEN_BINDINGS(my_module) 
    function("calculate", &calculate);

但如果我尝试调用 Module.calculate(0, ..., function()/*...*/) 我会收到此错误:

UnboundTypeError: Cannot call calculate due to unbound types: NSt3__18functionIFvvEEE

【问题讨论】:

在 emscripten GitHub 上有一个关于这个的线程,看起来可以使用 embind。 github.com/kripken/emscripten/issues/4927 【参考方案1】:

我不确定这是否是唯一的方法,但要从 Js -> C++ 传递回调,我必须这样做

不使用std::function,而是使用原始函数指针 使用 Runtime.addFunction 获取 javascript 函数的 C++ 函数指针,并将其传递到 C++ 世界,而不是尝试直接传递 Javascript 函数。 不使用EMBIND,而是使用cwrap/ccall API。

对于您的示例,稍微简化接口以便仅从 JS -> C++ 传递回调,C++ 可能如下所示:

extern "C" 

EMSCRIPTEN_KEEPALIVE
void calculate(void (*callback)()) 
  callback();



创建回调函数指针的 Javascript 可能如下所示

var callbackPointer = Module.Runtime.addFunction(function() 
  console.log('In the callback');
);

并调用函数,传递指针(作为“数字”):

Module.ccall('calculate', 'number', ['number'], [callbackPointer]);

然后编译确保为函数指针保留空间:

em++ app.cpp -s RESERVED_FUNCTION_POINTERS=1 -o app.js

【讨论】:

感谢您的帮助。但是如果我的calculate 函数是一个类方法,并且我想一次有更多实例呢? 您应该能够创建 C++ 对象并将指向它们的原始指针传递给 Javascript。然后,静态calculate 函数可以与回调的函数指针一起获取指向这些对象之一的指针。然后它将取消引用对象指针,并调用其实例calculate 方法。【参考方案2】:

您现在可以这样做:

void calculate(int param1, ..., emscripten::val callback) 
    callback();

EMSCRIPTEN_BINDINGS 没有改变。

回调甚至可以接受参数,只要它们是受支持/声明的类型(例如,如果您将 std::vector&lt;blah&gt; 参数传递给回调,请确保您已使用 register_vector&lt;blah&gt;()。)

【讨论】:

这个是最方便的方式,我写个样例可以参考sdk_web_assembly

以上是关于嵌入传递 lambda 函数作为回调参数的主要内容,如果未能解决你的问题,请参考以下文章

如何传递和使用任意lambda函数作为参数[重复]

在 C# 中将 lambda 函数作为命名参数传递

将 lambda 作为模板函数参数传递

函数名作为参数传递与回调函数

什么是lambda?有什么好处

将Lambda表达式作为参数传递并解析-在构造函数参数列表中使用Lambda表达式