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);