我确信必须有一个简单的答案,但我找不到任何关于文档或通过一些初步谷歌搜索的参考。
基本上,我有一个看起来像这样的课程:
#define NX 65
#define NY 65
class myclass{
// other stuff
public:
//other stuff.. more functions and more variables
// a function I want to call every so often with a few different cases
void solve(int case);
// a 2D double array that I want to access in JS
double ux[NX+1][NY+1];
}
还使用了其他函数和变量,但它们都不会直接在JavaScript中调用。
现在,我希望我们能够创建我的对象并执行以下操作:
x = new Module.myclass();
x.solve(2); // parameter is irrelevant
for (i=0; i<x.ux.length; i++) {
for (j=0; j<x.ux[i].length; j++) {
// do something with the data
console.log(x.ux[i][j]);
}
}
所以,我自然会这样做:
EMSCRIPTEN_BINDINGS(myclass) {
class_<myclass>("myclass")
.function("solve", &myclass::solve)
.property("ux", &LBM::getux, &LBM::setux)
;
}
这些是我的吸气剂和制定者
void setux(double uxnew[NX+1][NY+1]) {
for (int i=0; i<NX+1; i++) {
for (int j=0; j<NY+1; j++) {
ux[i][j] = uxnew[i][j];
}
}
};
double getux() { return **ux; };
然后有这些错误:
In file included from ../../lbm.cpp:10:
/home/vagrant/src/emscripten/system/include/emscripten/bind.h:1043:33: error: implicit instantiation of undefined template 'emscripten::internal::GetterPolicy<double (LBM::*)()>'
TypeID<typename GP::ReturnType>::get(),
^
../../lbm.cpp:1264:18: note: in instantiation of function template specialization 'emscripten::class_<LBM, emscripten::internal::NoBaseClass>::property<double (LBM::*)(), void (LBM::*)(double (*)[66])>' requested here
.property("p", &LBM::getp, &LBM::setp)
^
/home/vagrant/src/emscripten/system/include/emscripten/bind.h:428:16: note: template is declared here
struct GetterPolicy;
那么有谁知道如何在emscripten中处理双数组?我真的希望我不会错过部分文档。如果我没有,这确实需要包含在embind页面中。
另外,我为任何不连贯而道歉。这不是一个复杂的问题(表面上)。我只是不知道该怎么做。
答案 0 :(得分:3)
我认为你有几个选择,虽然不太可能......
此示例使用int的数组作为直接内存访问示例2,但只要在javascript端正确映射直接内存大小,就可以使用双精度或其他任何内容:
TEST.CPP:
#include <emscripten/bind.h>
#include <stdlib.h>
#include <iostream>
#define NX 65
#define NY 65
class myclass{
// other stuff
public:
myclass() {
//Just initializing some values to see:
ux2[0][0] = 3;
ux2[0][1] = 5;
ux2[1][0] = 7;
ux2[1][1] = 9;
}
//Example 1: only the setux seems to work, not getux:
std::vector<std::vector<double>> ux;
std::vector<std::vector<double>> getux() { return ux; }
void setux(std::vector<std::vector<double>> uxnew) {
for (int i=0; i<NX+1; i++) {
for (int j=0; j<NY+1; j++) {
std::cout << uxnew[i][j] << std::endl;
ux[i][j] = uxnew[i][j];
}
}
}
//Example 2: But if we know the address of ux2, then we can get
// the values and set them, no need for vector overhead:
int ux2[NX+1][NY+1];
int getux2() {
return (int)&ux2;
};
};
// Required for example 1:
EMSCRIPTEN_BINDINGS(stl_wrappers) {
emscripten::register_vector<double>("VectorDouble");
emscripten::register_vector<std::vector<double>>("VectorVectorDouble");
}
EMSCRIPTEN_BINDINGS(myclass) {
emscripten::class_<myclass>("myclass")
.constructor()
//// I could not seem to get properties to work with Vector or pointers:
//.property("ux", &myclass::getux, &myclass::setux)
//// So fell back to functions:
//// Example 1:
.function("setux",&myclass::setux)
.function("getux",&myclass::getux) // returns undefined?
//// Example 2: just work with pointers on JS side (note the allow_raw_pointers here)
.function("getux2",&myclass::getux2,emscripten::allow_raw_pointers())
;
};
test.js:
var M = require('./test.js');
var vdd = new M.VectorVectorDouble();
var doublearray = [];
for(var i=0; i<66; ++i){
var vd = new M.VectorDouble();
for(var j=0; j<66; ++j){
vd.push_back(i+j);
}
vdd.push_back(vd);
}
var testclass = new M.myclass();
//This works:
testclass.setux(vdd);
var noworkie = testclass.getux();
//But this does not: (?)
console.log(noworkie.get(0));
// Direct memory access:
var sz = 4;
var ln = 66;
var ind0 = 0;
var ind1 = 1;
var t = new M.myclass();
var ux2ptr = t.getux2();
console.log(M.getValue(ux2ptr+(0*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(0*ln + ind1)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind1)*sz,'i8*'));
M.setValue(ux2ptr+(0*ln + ind0)*sz,10,'i8*');
console.log(M.getValue(ux2ptr+(0*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(0*ln + ind1)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind0)*sz,'i8*'));
console.log(M.getValue(ux2ptr+(1*ln + ind1)*sz,'i8*'));
emcc test.cpp -o test.js -std = c ++ 11 --bind
向量看起来更像是一种痛苦并且增加了开销,而不仅仅是直接内存访问,所以我可能只是提供一些javascript指针算术函数,使用直接访问转换为必要的类型,并返回来自C ++函数的指针它更容易使用。这样你就可以做到:
var dimension1 = NX+1, dimension2 = NY+1;
var blah = doubleptrptr(ux2ptr, dimension1, dimension2);
var first = blah[0][0]; // so you can use the way you expect on the js side.
哦顺便说一下:
emcc -v
emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 2.0
clang version 3.2 (tags/RELEASE_32/final)
Target: i386-pc-linux-gnu
Thread model: posix
<强>更新强>
使用2d数组而不是int的示例。函数的返回类型仍然是int,因为它通过&符号运算符返回事物的地址。与其数据类型无关,所有数据类型都具有相同大小的指针。有趣的是emscripten如何模拟整个指针概念,在JS代码中考虑它是一种很好的方式:)无论如何,无论它是什么,你都可以将它作为int返回。
//Example 2: If we know the address of ux2, then we can get
// the values and set them, no need for vector overhead:
double p[NX+1][NY+1];
int getp() {
return (int)&p;
};
所以唯一改变的是ux2声明中的数据类型,你仍然得到ux2的地址并将其作为int返回,可能不需要演员但是什么哎,不会伤。
确保在emscripten绑定中执行 allow_raw_pointers :
.function("getp",&myclass::getp,emscripten::allow_raw_pointers())
正如我所提到的,当你的示例中有属性时,我无法弄清楚怎么告诉它做allow_raw_pointers,所以我只使用了上面例子中显示的函数。