From b538070016e46e463b3897fbdb75e1ae995f936e Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Sun, 22 Jan 2017 10:29:34 +0000 Subject: [PATCH] Enhance %extend to extend a class with template methods --- CHANGES.current | 13 ++++ Doc/Manual/SWIGPlus.html | 37 +++++++++++ Examples/test-suite/common.mk | 1 + Examples/test-suite/extend_template_method.i | 62 +++++++++++++++++++ .../java/extend_template_method_runme.java | 57 +++++++++++++++++ .../python/extend_template_method_runme.py | 36 +++++++++++ Source/Modules/lang.cxx | 2 +- 7 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 Examples/test-suite/extend_template_method.i create mode 100644 Examples/test-suite/java/extend_template_method_runme.java create mode 100644 Examples/test-suite/python/extend_template_method_runme.py diff --git a/CHANGES.current b/CHANGES.current index 9a078cc71..68d578915 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,19 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 3.0.12 (in progress) ============================ +2017-01-22: wsfulton + Issue #876 Enhance %extend to extend a class with template methods, eg: + + struct Foo { + %extend { + template + void do_stuff(int a, T b) { + ... + } + } + }; + %template(do_stuff_inst) Foo::do_stuff; + 2017-01-22: kwwette [Octave] add support for version 4.2 - The Octave API now uses some C++11 features. It is recommended to use diff --git a/Doc/Manual/SWIGPlus.html b/Doc/Manual/SWIGPlus.html index 6fe9c2909..3e7860b9b 100644 --- a/Doc/Manual/SWIGPlus.html +++ b/Doc/Manual/SWIGPlus.html @@ -3635,6 +3635,43 @@ This will generate two overloaded wrapper methods, the first will take a single and the second will take two integer arguments.

+

+It is even possible to extend a class via %extend with template methods, for example: +

+ +
+
+%include <std_string.i>
+
+%inline %{
+class ExtendMe {
+public:
+  template <typename T>
+  T do_stuff_impl(int a, T b, double d) {
+    return b;
+  }
+};
+%}
+
+%extend ExtendMe {
+  template<typename T>
+  T do_overloaded_stuff(T b) {
+    return $self->do_stuff_impl(0, b, 4.0);
+  }
+}
+%template(do_overloaded_stuff) ExtendMe::do_overloaded_stuff<std::string>;
+%template(do_overloaded_stuff) ExtendMe::do_overloaded_stuff<double>;
+
+
+ +

+The wrapped ExtendMe class will then have two (overloaded) methods called do_overloaded_stuff. +

+ +

+Compatibility Note: Extending a class with template methods was added in version 3.0.12 +

+

Needless to say, SWIG's template support provides plenty of opportunities to break the universe. That said, an important final point is that SWIG does diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index e1452bbb7..8d97b4bf9 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -227,6 +227,7 @@ CPP_TEST_CASES += \ extend_placement \ extend_special_variables \ extend_template \ + extend_template_method \ extend_template_ns \ extend_typedef_class \ extern_c \ diff --git a/Examples/test-suite/extend_template_method.i b/Examples/test-suite/extend_template_method.i new file mode 100644 index 000000000..e1253606a --- /dev/null +++ b/Examples/test-suite/extend_template_method.i @@ -0,0 +1,62 @@ +%module extend_template_method + +%include + +%inline %{ +class ExtendMe { +public: + template + T do_stuff_impl(int a, T b, double d) { + return b; + } +}; +%} + +%extend ExtendMe { + template + T do_stuff(int a, T b) { + return $self->do_stuff_impl(a, b, 4.0); + } + template + T do_overloaded_stuff(T b) { + return $self->do_stuff_impl(0, b, 4.0); + } +} +%template(do_stuff_double) ExtendMe::do_stuff; +%template(do_stuff_string) ExtendMe::do_stuff; + +%template(do_overloaded_stuff) ExtendMe::do_overloaded_stuff; +%template(do_overloaded_stuff) ExtendMe::do_overloaded_stuff; + + +%inline %{ +template +class TemplateExtendMe { +public: + template + T template_stuff_impl(X a, T b, double d) { + return b; + } +}; +%} + +%extend TemplateExtendMe { + template + T do_template_stuff(int a, T b) { + return $self->template_stuff_impl(a, b, 4.0); + } + template + T do_template_overloaded_stuff(T b) { + return $self->template_stuff_impl(0, b, 4.0); + } + +%template(do_template_stuff_double) do_template_stuff; +%template(do_template_stuff_string) do_template_stuff; + +%template(do_template_overloaded_stuff) do_template_overloaded_stuff; +%template(do_template_overloaded_stuff) do_template_overloaded_stuff; + +} + +%template(TemplateExtend) TemplateExtendMe; + diff --git a/Examples/test-suite/java/extend_template_method_runme.java b/Examples/test-suite/java/extend_template_method_runme.java new file mode 100644 index 000000000..cf21cd7b1 --- /dev/null +++ b/Examples/test-suite/java/extend_template_method_runme.java @@ -0,0 +1,57 @@ + +import extend_template_method.*; + +public class extend_template_method_runme { + + static { + try { + System.loadLibrary("extend_template_method"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + { + ExtendMe em = new ExtendMe(); + + { + double ret_double = em.do_stuff_double(1, 1.1); + if (ret_double != 1.1) + throw new RuntimeException("double failed " + ret_double); + String ret_string = em.do_stuff_string(1, "hello there"); + if (!ret_string.equals("hello there")) + throw new RuntimeException("string failed " + ret_string); + } + { + double ret_double = em.do_overloaded_stuff(1.1); + if (ret_double != 1.1) + throw new RuntimeException("double failed " + ret_double); + String ret_string = em.do_overloaded_stuff("hello there"); + if (!ret_string.equals("hello there")) + throw new RuntimeException("string failed " + ret_string); + } + } + { + TemplateExtend em = new TemplateExtend(); + + { + double ret_double = em.do_template_stuff_double(1, 1.1); + if (ret_double != 1.1) + throw new RuntimeException("double failed " + ret_double); + String ret_string = em.do_template_stuff_string(1, "hello there"); + if (!ret_string.equals("hello there")) + throw new RuntimeException("string failed " + ret_string); + } + { + double ret_double = em.do_template_overloaded_stuff(1.1); + if (ret_double != 1.1) + throw new RuntimeException("double failed " + ret_double); + String ret_string = em.do_template_overloaded_stuff("hello there"); + if (!ret_string.equals("hello there")) + throw new RuntimeException("string failed " + ret_string); + } + } + } +} diff --git a/Examples/test-suite/python/extend_template_method_runme.py b/Examples/test-suite/python/extend_template_method_runme.py new file mode 100644 index 000000000..eb7a6d654 --- /dev/null +++ b/Examples/test-suite/python/extend_template_method_runme.py @@ -0,0 +1,36 @@ +from extend_template_method import * + + +em = ExtendMe() + +ret_double = em.do_stuff_double(1, 1.1) +if ret_double != 1.1: + raise RuntimeError("double failed " + ret_double) +ret_string = em.do_stuff_string(1, "hello there") +if ret_string != "hello there": + raise RuntimeError("string failed " + ret_string) + +ret_double = em.do_overloaded_stuff(1.1) +if ret_double != 1.1: + raise RuntimeError("double failed " + ret_double) +ret_string = em.do_overloaded_stuff("hello there") +if ret_string != "hello there": + raise RuntimeError("string failed " + ret_string) + + +em = TemplateExtend() + +ret_double = em.do_template_stuff_double(1, 1.1) +if ret_double != 1.1: + raise RuntimeError("double failed " + ret_double) +ret_string = em.do_template_stuff_string(1, "hello there") +if ret_string != "hello there": + raise RuntimeError("string failed " + ret_string) + + +ret_double = em.do_template_overloaded_stuff(1.1) +if ret_double != 1.1: + raise RuntimeError("double failed " + ret_double) +ret_string = em.do_template_overloaded_stuff("hello there") +if ret_string != "hello there": + raise RuntimeError("string failed " + ret_string) diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index 57b0d50e6..5dad125e0 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -1267,7 +1267,7 @@ int Language::memberfunctionHandler(Node *n) { if (GetFlag(n, "explicitcall")) DirectorExtraCall = CWRAP_DIRECTOR_ONE_CALL; - Swig_MethodToFunction(n, NSpace, ClassType, Getattr(n, "template") ? SmartPointer : Extend | SmartPointer | DirectorExtraCall, director_type, + Swig_MethodToFunction(n, NSpace, ClassType, Getattr(n, "template") ? Extend | SmartPointer : Extend | SmartPointer | DirectorExtraCall, director_type, is_member_director(CurrentClass, n)); Setattr(n, "sym:name", fname);