如何通过WASM和Emscripten从JS向C++传递vector<class>?
解决Emscripten中JavaScript向C++传递
vector<A>的问题 关键原理
Emscripten不会自动将JS数组隐式转换为C的std::vector<A>,必须通过Emscripten绑定生成的vector包装类来创建和填充实例,或者在C端添加适配JS数组的辅助函数。
步骤1:确认C++绑定代码的正确性
确保你已经正确注册了vector<A>的包装类,Emscripten的register_vector模板需要传入元素类型(而非别名):
#include <emscripten/bind.h> #include <vector> class A { public: int x; A(int x_) : x(x_) {} }; using AVector = std::vector<A>; namespace util { class Print { public: static void print(const AVector& vec) { for (const auto& a : vec) { printf("A.x = %d\n", a.x); } } }; } EMSCRIPTEN_BINDINGS(my_module) { // 注册A类 emscripten::class_<A>("A") .constructor<int>() .property("x", &A::x); // 注册vector<A>为AVector(关键:模板参数是元素类型A) emscripten::register_vector<A>("AVector"); // 注册Print类的静态方法 emscripten::class_<util::Print>("Print") .class_function("print", &util::Print::print); }
步骤2:JavaScript端的正确实现
方式1:通过AVector包装类创建并填充
直接使用Emscripten生成的AVector构造函数和push_back方法来构建实例:
// 假设Module是Emscripten加载完成后的模块对象 function passVectorToCpp() { // 创建空的AVector实例 const cppVector = new Module.AVector(); // 向vector中添加A类实例 cppVector.push_back(new Module.A(10)); cppVector.push_back(new Module.A(20)); cppVector.push_back(new Module.A(30)); // 调用C++的Print.print方法 Module.Print.print(cppVector); } // 等待WASM模块初始化完成后执行 Module.onRuntimeInitialized = passVectorToCpp;
方式2:将JS数组转换为AVector
如果已有JS数组,遍历数组逐个创建A实例并添加到AVector中:
function convertJsArrayToCppVector(jsArray) { const cppVector = new Module.AVector(); jsArray.forEach(item => { // 从JS对象的x属性创建A实例 const aInstance = new Module.A(item.x); cppVector.push_back(aInstance); }); return cppVector; } // 使用示例 const jsData = [{x: 5}, {x: 15}, {x: 25}]; const convertedVec = convertJsArrayToCppVector(jsData); Module.Print.print(convertedVec);
方式3:C++端添加适配函数(支持直接传JS数组)
如果想简化JS端代码,可以在C++中新增一个接受emscripten::val的重载方法,自动处理JS数组到vector<A>的转换:
// 在util::Print类中添加重载 static void print(const emscripten::val& jsArray) { AVector vec; const size_t len = jsArray["length"].as<size_t>(); for (size_t i = 0; i < len; ++i) { emscripten::val aVal = jsArray[i]; int x = aVal["x"].as<int>(); vec.emplace_back(x); } print(vec); // 调用原有的print方法 }
此时JS端可以直接传递普通数组:
Module.Print.print([{x: 1}, {x: 2}, {x: 3}]);
常见错误原因
new AVector()无构造签名:未在C++绑定中调用register_vector<A>("AVector"),导致Emscripten未生成对应的JS包装类构造函数。- 普通JS数组无法传入:JS数组与C++
std::vector内存结构完全不同,Emscripten不支持隐式转换,必须通过包装类或适配函数处理。
内容的提问来源于stack exchange,提问作者ayush bansal
相关产品推荐
相关产品推荐

