I would like to create a function, which calculates something. And after it's finished, it calls the callback function.
void calculate(int param1, ..., std::function<void(void)> callback) {
//code...
callback();
}
The binding of the function is created using Embind
:
EMSCRIPTEN_BINDINGS(my_module) {
function("calculate", &calculate);
}
But if I try to call Module.calculate(0, ..., function(){/*...*/})
I get this error:
UnboundTypeError: Cannot call calculate due to unbound types: NSt3__18functionIFvvEEE
I would like to create a function, which calculates something. And after it's finished, it calls the callback function.
void calculate(int param1, ..., std::function<void(void)> callback) {
//code...
callback();
}
The binding of the function is created using Embind
:
EMSCRIPTEN_BINDINGS(my_module) {
function("calculate", &calculate);
}
But if I try to call Module.calculate(0, ..., function(){/*...*/})
I get this error:
UnboundTypeError: Cannot call calculate due to unbound types: NSt3__18functionIFvvEEE
Share
Improve this question
asked Apr 2, 2016 at 8:49
Iter AtorIter Ator
9,33421 gold badges89 silver badges183 bronze badges
1
- There is a thread about this on the emscripten GitHub, looks like it is possible using embind. github./kripken/emscripten/issues/4927 – abcthomas Commented Aug 23, 2017 at 14:27
3 Answers
Reset to default 5I'm not sure if it's the only way, but to pass callbacks from Js -> C++, I've had to
- Not use
std::function
, but raw function pointers - Use
Runtime.addFunction
to get a C++ function pointer for a Javascript function, and pass that into the C++ world instead of trying to pass a Javascript function directly. - Not use
EMBIND
, but rather thecwrap
/ccall
API.
For your example, simplifying the interface slightly so only the callback is passed from JS -> C++, the C++ could look like the following:
extern "C" {
EMSCRIPTEN_KEEPALIVE
void calculate(void (*callback)()) {
callback();
}
}
The Javascript to create the callback function pointer could look like
var callbackPointer = Module.Runtime.addFunction(function() {
console.log('In the callback');
});
and to call the function, passing the pointer (as a "number"):
Moduleall('calculate', 'number', ['number'], [callbackPointer]);
and then piling making sure to reserve room for the function pointer:
em++ app.cpp -s RESERVED_FUNCTION_POINTERS=1 -o app.js
You can now do it like this:
void calculate(int param1, ..., emscripten::val callback) {
callback();
}
The EMSCRIPTEN_BINDINGS
is unchanged.
The callback can even take parameters, provided they are of supported/declared types (e.g. if you pass an std::vector<blah>
parameter to the callback, make sure you've used register_vector<blah>()
.)
You can use Scapix to pass parameters like std::function
, std::vector
, std::map
, etc.
In addition to generating bindings automatically, Scapix also adds conversion layer for (arbitrarily nested) mon C++ Standard Library types.
Disclaimer: I am the author of Scapix Language Bridge.