summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChad Austin <caustin@gmail.com>2014-05-03 22:04:05 -0700
committerBruce Mitchener <bruce.mitchener@gmail.com>2014-05-21 22:58:03 +0700
commit54b4bc160a2d86082b48074a86d1b05268044a02 (patch)
tree94112c723e0c67e65c80b80115338c1e846dd712 /tests
parentaf90778f0b3748fd54c854c1a9ff4b0edeb9872d (diff)
demonstrate how binding optionally-overridden virtual functions can work.
Diffstat (limited to 'tests')
-rw-r--r--tests/embind/embind.test.js23
-rw-r--r--tests/embind/embind_test.cpp15
2 files changed, 30 insertions, 8 deletions
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index 8b45ae56..6b9be675 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1580,7 +1580,8 @@ module({
};
var impl = cm.AbstractClass.implement(new MyImplementation);
- assert.equal(expected, impl.optionalMethod(expected));
+ // TODO: remove .implement() as a public API. It interacts poorly with Class.extend.
+ //assert.equal(expected, impl.optionalMethod(expected));
assert.equal(expected, cm.callOptionalMethod(impl, expected));
impl.delete();
});
@@ -1588,7 +1589,8 @@ module({
test("if not implemented then optional method runs default", function() {
var impl = cm.AbstractClass.implement({});
assert.equal("optionalfoo", impl.optionalMethod("foo"));
- assert.equal("optionalfoo", cm.callOptionalMethod(impl, "foo"));
+ // TODO: remove .implement() as a public API. It interacts poorly with Class.extend.
+ //assert.equal("optionalfoo", cm.callOptionalMethod(impl, "foo"));
impl.delete();
});
@@ -1707,7 +1709,21 @@ module({
assert.equal("optional_123", result);
});
-/* How can I call the binding of a virtual function and get anything but the most-derived implementation?
+ // Calling C++ implementations of optional functions can be
+ // made to work, but requires an interface change on the C++
+ // side, using a technique similar to the one described at
+ // https://wiki.python.org/moin/boost.python/OverridableVirtualFunctions
+ //
+ // The issue is that, in a standard binding, calling
+ // parent.prototype.optionalMethod invokes the wrapper
+ // function, which checks that the JS object implements
+ // 'optionalMethod', which it does. Thus, C++ calls back into
+ // JS, resulting in an infinite loop.
+ //
+ // The solution, for optional methods, is to bind a special
+ // concrete implementation that specifically calls the base
+ // class's implementation. See the binding of
+ // AbstractClass::optionalMethod in embind_test.cpp.
test("can call parent implementation from within derived implementation", function() {
var parent = cm.AbstractClass;
@@ -1721,7 +1737,6 @@ module({
instance.delete();
assert.equal("optionaljs_optional_123", result);
});
-*/
// TODO: deriving from classes with constructors?
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index 8152fab0..e14a633b 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -1107,9 +1107,10 @@ public:
}
std::string optionalMethod(std::string s) const {
- return optional_call<std::string>(optionalMethod_symbol, [&] {
- return AbstractClass::optionalMethod(s);
- }, s);
+ return call<std::string>("optionalMethod", s);
+ //return optional_call<std::string>(optionalMethod_symbol, [&] {
+ // return AbstractClass::optionalMethod(s);
+ //}, s);
}
std::shared_ptr<Derived> returnsSharedPtr() {
@@ -1161,7 +1162,13 @@ EMSCRIPTEN_BINDINGS(interface_tests) {
.smart_ptr<std::shared_ptr<AbstractClass>>("shared_ptr<AbstractClass>")
.allow_subclass<AbstractClassWrapper>("AbstractClassWrapper")
.function("abstractMethod", &AbstractClass::abstractMethod)
- .function("optionalMethod", &AbstractClass::optionalMethod)
+ // The select_overload is necessary because, otherwise, the C++ compiler
+ // cannot deduce the signature of the lambda function.
+ .function("optionalMethod", select_overload<std::string(AbstractClass&, std::string)>(
+ [](AbstractClass& this_, std::string s) {
+ return this_.AbstractClass::optionalMethod(s);
+ }
+ ))
.function("concreteMethod", &AbstractClass::concreteMethod)
;