如何为接收std::function&&的函数创建Emscripten绑定?
错误原因
Emscripten默认没有提供std::function类型和JS函数的自动转换规则,因此绑定器无法识别std::function<void()>类型,无法完成JS参数到C++参数的转换,就会抛出你遇到的BindingError报错。另外你代码里的allow_subclass方法中FooWraper拼写错误,少了一个p,正确拼写为FooWrapper,这个错误也可能导致绑定失效。
解决方案
方案1:不修改原有C++接口,手动添加转换逻辑
不需要修改原Foo类的定义,只需要调整绑定代码,把JS传入的函数用emscripten::val接收后手动包装为std::function<void()>即可。
首先添加必要头文件:
#include <emscripten/val.h> #include <emscripten/bind.h> using namespace emscripten;
然后修改绑定代码:
struct FooWrapper : public wrapper<Foo> { EMSCRIPTEN_WRAPPER(FooWrapper); void bar(std::function<void()> &&func) override { call<void>("bar", std::move(func)); } }; EMSCRIPTEN_BINDINGS(Foo) { class_<Foo>("Foo") .smart_ptr<Foo>("Foo") // 手动绑定bar方法,适配JS函数输入 .function("bar", optional_override([](Foo& self, val js_func) { // 将JS函数包装为std::function std::function<void()> cpp_func = [js_func = std::move(js_func)]() mutable { js_func(); }; self.bar(std::move(cpp_func)); })) // 修正拼写错误 .allow_subclass<FooWrapper, std::shared_ptr<FooWrapper>>("FooWrapper", "FooWrapperSharedPtr"); }
方案2:修改接口直接使用emscripten::val
如果允许调整原Foo类的接口,可以直接把参数类型替换为emscripten::val,省去类型转换的步骤,性能也更高:
#include <emscripten/val.h> using namespace emscripten; class Foo { virtual void bar(val func) = 0; }; // 调用时直接执行即可 void FooWrapper::bar(val func) override { // 同步调用JS函数 func(); // 如果需要异步调用,直接存下val实例即可,不需要额外处理生命周期 }
绑定的时候不需要额外处理,直接注册类即可,JS侧的调用方式完全不变。
注意事项
如果你的std::function带有参数或者有返回值,只需要在lambda中增加对应的参数转换逻辑即可,比如std::function<int(std::string)>对应的包装逻辑为:
std::function<int(std::string)> cpp_func = [js_func = std::move(js_func)](std::string arg) { return js_func(arg).as<int>(); };
内容的提问来源于stack exchange,提问作者Quentamia
相关产品推荐
相关产品推荐

