diff options
author | Chad Austin <caustin@gmail.com> | 2014-05-03 22:04:05 -0700 |
---|---|---|
committer | Bruce Mitchener <bruce.mitchener@gmail.com> | 2014-05-21 22:58:03 +0700 |
commit | 54b4bc160a2d86082b48074a86d1b05268044a02 (patch) | |
tree | 94112c723e0c67e65c80b80115338c1e846dd712 /tests | |
parent | af90778f0b3748fd54c854c1a9ff4b0edeb9872d (diff) |
demonstrate how binding optionally-overridden virtual functions can work.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/embind/embind.test.js | 23 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 15 |
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) ; |