使用2D双数组绑定类时出现Emscripten错误

时间:2013-06-12 02:06:21

标签: emscripten

我确信必须有一个简单的答案,但我找不到任何关于文档或通过一些初步谷歌搜索的参考。

基本上,我有一个看起来像这样的课程:

#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页面中。

另外,我为任何不连贯而道歉。这不是一个复杂的问题(表面上)。我只是不知道该怎么做。

1 个答案:

答案 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,所以我只使用了上面例子中显示的函数。