mirror of https://github.com/swig/swig
Add support for using declarations to introduce templated members
Add support for using declarations to introduce templated member methods and for inheriting templated constructors, such as: struct Base { // templated constructor template <typename T> Base(const T &t, const char *s) {} // templated member method template <typename T> void template_method(const T &t, const char *s) {} }; %template(Base) Base::Base<int>; %template(template_method) Base::template_method<double>; struct Derived : Base { using Base::Base; using Base::template_method; }; Previously the templated methods and constructors were ignored and not introduced into the Derived class.
This commit is contained in:
parent
93732bb195
commit
2e1506c189
|
@ -7,6 +7,28 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-08-06: wsfulton
|
||||
Add support for using declarations to introduce templated member
|
||||
methods and for inheriting templated constructors, such as:
|
||||
|
||||
struct Base {
|
||||
// templated constructor
|
||||
template <typename T> Base(const T &t, const char *s) {}
|
||||
// templated member method
|
||||
template <typename T> void template_method(const T &t, const char *s) {}
|
||||
};
|
||||
|
||||
%template(Base) Base::Base<int>;
|
||||
%template(template_method) Base::template_method<double>;
|
||||
|
||||
struct Derived : Base {
|
||||
using Base::Base;
|
||||
using Base::template_method;
|
||||
};
|
||||
|
||||
Previously the templated methods and constructors were ignored and
|
||||
not introduced into the Derived class.
|
||||
|
||||
2023-08-04: wsfulton
|
||||
Fix using declarations for inheritance hierarchies more than
|
||||
two deep and the using declarations are overloaded. Using declarations
|
||||
|
|
|
@ -510,35 +510,56 @@ struct TemplPublicDerived6 : TemplPublicBase6<T> {
|
|||
%template(TemplPublicDerived6Int) TemplPublicDerived6<int>;
|
||||
|
||||
|
||||
// Templated constructors
|
||||
// Templated constructors (public)
|
||||
%inline %{
|
||||
struct TemplateConstructor1Base {
|
||||
virtual ~TemplateConstructor1Base() {}
|
||||
public:
|
||||
// No implicit constructor
|
||||
template <typename T> TemplateConstructor1Base(const T &t, const char *s) {}
|
||||
virtual void meth() {}
|
||||
template <typename T> TemplateConstructor1Base(T t, const char *s) {}
|
||||
template <typename T> void template_method(T t, const char *s) {}
|
||||
virtual void normal_method() {}
|
||||
};
|
||||
%}
|
||||
|
||||
%template(TemplateConstructor1Base) TemplateConstructor1Base::TemplateConstructor1Base<int>;
|
||||
%template(TemplateConstructor1Base) TemplateConstructor1Base::TemplateConstructor1Base<const char *>;
|
||||
%template(TemplateConstructor1Base) TemplateConstructor1Base::TemplateConstructor1Base<double>;
|
||||
%template(template_method) TemplateConstructor1Base::template_method<int>;
|
||||
%template(template_method) TemplateConstructor1Base::template_method<const char *>;
|
||||
|
||||
%inline %{
|
||||
struct TemplateConstructor1Derived : TemplateConstructor1Base {
|
||||
using TemplateConstructor1Base::normal_method;
|
||||
// Note: The two using declarations below automatically introduce the templated names without an explicit %template(), see allocate.cxx
|
||||
using TemplateConstructor1Base::TemplateConstructor1Base;
|
||||
using TemplateConstructor1Base::meth;
|
||||
using TemplateConstructor1Base::template_method;
|
||||
};
|
||||
%}
|
||||
|
||||
// TODO: Missing constructors, below probably ought to work using instantiation as follows:
|
||||
//%template(TemplateConstructor1Derived) TemplateConstructor1Derived::TemplateConstructor1Derived<int>;
|
||||
|
||||
%{
|
||||
void tester() {
|
||||
TemplateConstructor1Derived tc = TemplateConstructor1Derived(123, "hi");
|
||||
tc.meth();
|
||||
// Note not valid c++:
|
||||
// TemplateConstructor1Derived tc2 = TemplateConstructor1Derived::TemplateConstructor1Derived<int>(123, "hi");
|
||||
}
|
||||
// Templated constructors (protected)
|
||||
%inline %{
|
||||
struct TemplateConstructor2Base {
|
||||
virtual ~TemplateConstructor2Base() {}
|
||||
protected:
|
||||
// No implicit constructor
|
||||
template <typename T> TemplateConstructor2Base(T t, const char *s) {}
|
||||
template <typename T> void template_method(T t, const char *s) {}
|
||||
virtual void normal_method() {}
|
||||
};
|
||||
%}
|
||||
|
||||
// Note that templated methods also not working with using declarations for inheriting from base templated methods
|
||||
%template(TemplateConstructor2Base) TemplateConstructor2Base::TemplateConstructor2Base<int>;
|
||||
%template(TemplateConstructor2Base) TemplateConstructor2Base::TemplateConstructor2Base<const char *>;
|
||||
%template(TemplateConstructor2Base) TemplateConstructor2Base::TemplateConstructor2Base<double>;
|
||||
%template(template_method) TemplateConstructor2Base::template_method<int>;
|
||||
%template(template_method) TemplateConstructor2Base::template_method<const char *>;
|
||||
|
||||
%inline %{
|
||||
struct TemplateConstructor2Derived : TemplateConstructor2Base {
|
||||
using TemplateConstructor2Base::normal_method;
|
||||
using TemplateConstructor2Base::TemplateConstructor2Base; // introduces protected constructors
|
||||
using TemplateConstructor2Base::template_method; // introduces public templated methods
|
||||
TemplateConstructor2Derived() : TemplateConstructor2Derived(0, "") {} // provide one public constructor for testing
|
||||
};
|
||||
%}
|
||||
|
|
|
@ -114,7 +114,7 @@ public class cpp11_director_using_constructor_runme {
|
|||
DeepProtectedBase3 dbp3 = new DeepProtectedBase3(11, 22, 33);
|
||||
|
||||
// Missing base
|
||||
// new HiddenDerived1();
|
||||
new HiddenDerived1();
|
||||
|
||||
// Templates and public base constructors (derive from non-template)
|
||||
new TemplatePublicDerived1Int(0, "hi").meth();
|
||||
|
@ -135,6 +135,38 @@ public class cpp11_director_using_constructor_runme {
|
|||
new TemplPublicDerived5Int().meth();
|
||||
new TemplPublicDerived6Int(0, "hi").meth();
|
||||
new TemplPublicDerived6Int().meth();
|
||||
|
||||
// Templated constructors (public)
|
||||
TemplateConstructor1Base tcb = new TemplateConstructor1Base(0, "hi");
|
||||
tcb = new TemplateConstructor1Base("hi", "hi");
|
||||
tcb = new TemplateConstructor1Base(11.1, "hi");
|
||||
tcb.normal_method();
|
||||
tcb.template_method(0, "hi");
|
||||
tcb.template_method("hey", "ho");
|
||||
|
||||
TemplateConstructor1Derived tcd1 = new TemplateConstructor1Derived(0, "hi");
|
||||
tcd1 = new TemplateConstructor1Derived("hi", "hi");
|
||||
tcd1 = new TemplateConstructor1Derived(11.1, "hi");
|
||||
// Not the best test as these are also in the base class, hence use also introspection below
|
||||
tcd1.normal_method();
|
||||
tcd1.template_method(0, "hi");
|
||||
tcd1.template_method("hey", "ho");
|
||||
|
||||
// Templated methods
|
||||
// Introspection to make sure these are actually generated in the derived class
|
||||
try {
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("normal_method", (java.lang.Class[])null);
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("template_method", new java.lang.Class[]{String.class, String.class});
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("template_method", new java.lang.Class[]{int.class, String.class});
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// Templated constructors (protected)
|
||||
TemplateConstructor2Derived tcd2 = new TemplateConstructor2Derived();
|
||||
tcd2.normal_method();
|
||||
tcd2.template_method(0, "hi");
|
||||
tcd2.template_method("hey", "ho");
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
import cpp11_using_constructor.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class cpp11_using_constructor_runme {
|
||||
|
||||
|
@ -112,7 +113,7 @@ public class cpp11_using_constructor_runme {
|
|||
DeepProtectedBase3 dbp3 = new DeepProtectedBase3(11, 22, 33);
|
||||
|
||||
// Missing base
|
||||
// new HiddenDerived1();
|
||||
new HiddenDerived1();
|
||||
|
||||
// Templates and public base constructors (derive from non-template)
|
||||
new TemplatePublicDerived1Int(0, "hi").meth();
|
||||
|
@ -134,9 +135,36 @@ public class cpp11_using_constructor_runme {
|
|||
new TemplPublicDerived6Int(0, "hi").meth();
|
||||
new TemplPublicDerived6Int().meth();
|
||||
|
||||
// Templated constructors
|
||||
new TemplateConstructor1Base(0, "hi").meth();
|
||||
// TODO: missing constructor...
|
||||
// new TemplateConstructor1Derived(0, "hi").meth();
|
||||
// Templated constructors (public)
|
||||
TemplateConstructor1Base tcb = new TemplateConstructor1Base(0, "hi");
|
||||
tcb = new TemplateConstructor1Base("hi", "hi");
|
||||
tcb = new TemplateConstructor1Base(11.1, "hi");
|
||||
tcb.normal_method();
|
||||
tcb.template_method(0, "hi");
|
||||
tcb.template_method("hey", "ho");
|
||||
|
||||
TemplateConstructor1Derived tcd1 = new TemplateConstructor1Derived(0, "hi");
|
||||
tcd1 = new TemplateConstructor1Derived("hi", "hi");
|
||||
tcd1 = new TemplateConstructor1Derived(11.1, "hi");
|
||||
// Not the best test as these are also in the base class, hence use also introspection below
|
||||
tcd1.normal_method();
|
||||
tcd1.template_method(0, "hi");
|
||||
tcd1.template_method("hey", "ho");
|
||||
|
||||
// Templated methods
|
||||
// Introspection to make sure these are actually generated in the derived class
|
||||
try {
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("normal_method", (java.lang.Class[])null);
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("template_method", new java.lang.Class[]{String.class, String.class});
|
||||
TemplateConstructor1Derived.class.getDeclaredMethod("template_method", new java.lang.Class[]{int.class, String.class});
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// Templated constructors (protected)
|
||||
TemplateConstructor2Derived tcd2 = new TemplateConstructor2Derived();
|
||||
tcd2.normal_method();
|
||||
tcd2.template_method(0, "hi");
|
||||
tcd2.template_method("hey", "ho");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ db3 = DeepBase3(11, 22, 33)
|
|||
dbp3 = DeepProtectedBase3(11, 22, 33)
|
||||
|
||||
# Missing base
|
||||
# HiddenDerived1()
|
||||
HiddenDerived1()
|
||||
|
||||
# Templates and public base constructors (derive from non-template)
|
||||
TemplatePublicDerived1Int(0, "hi").meth()
|
||||
|
@ -121,3 +121,25 @@ TemplPublicDerived4Int().meth()
|
|||
TemplPublicDerived5Int().meth()
|
||||
TemplPublicDerived6Int(0, "hi").meth()
|
||||
TemplPublicDerived6Int().meth()
|
||||
|
||||
# Templated constructors (public)
|
||||
tcb = TemplateConstructor1Base(0, "hi")
|
||||
tcb = TemplateConstructor1Base("hi", "hi")
|
||||
tcb = TemplateConstructor1Base(11.1, "hi")
|
||||
tcb.normal_method()
|
||||
tcb.template_method(0, "hi")
|
||||
tcb.template_method("hey", "ho")
|
||||
|
||||
tcd1 = TemplateConstructor1Derived(0, "hi")
|
||||
tcd1 = TemplateConstructor1Derived("hi", "hi")
|
||||
tcd1 = TemplateConstructor1Derived(11.1, "hi")
|
||||
# Not the best test as these are also in the base class, (should use introspection to check)
|
||||
tcd1.normal_method()
|
||||
tcd1.template_method(0, "hi")
|
||||
tcd1.template_method("hey", "ho")
|
||||
|
||||
# Templated constructors (protected)
|
||||
tcd2 = TemplateConstructor2Derived()
|
||||
tcd2.normal_method()
|
||||
tcd2.template_method(0, "hi")
|
||||
tcd2.template_method("hey", "ho")
|
||||
|
|
|
@ -100,7 +100,7 @@ db3 = DeepBase3(11, 22, 33)
|
|||
dbp3 = DeepProtectedBase3(11, 22, 33)
|
||||
|
||||
# Missing base
|
||||
# HiddenDerived1()
|
||||
HiddenDerived1()
|
||||
|
||||
# Templates and public base constructors (derive from non-template)
|
||||
TemplatePublicDerived1Int(0, "hi").meth()
|
||||
|
@ -121,3 +121,25 @@ TemplPublicDerived4Int().meth()
|
|||
TemplPublicDerived5Int().meth()
|
||||
TemplPublicDerived6Int(0, "hi").meth()
|
||||
TemplPublicDerived6Int().meth()
|
||||
|
||||
# Templated constructors (public)
|
||||
tcb = TemplateConstructor1Base(0, "hi")
|
||||
tcb = TemplateConstructor1Base("hi", "hi")
|
||||
tcb = TemplateConstructor1Base(11.1, "hi")
|
||||
tcb.normal_method()
|
||||
tcb.template_method(0, "hi")
|
||||
tcb.template_method("hey", "ho")
|
||||
|
||||
tcd1 = TemplateConstructor1Derived(0, "hi")
|
||||
tcd1 = TemplateConstructor1Derived("hi", "hi")
|
||||
tcd1 = TemplateConstructor1Derived(11.1, "hi")
|
||||
# Not the best test as these are also in the base class, (should use introspection to check)
|
||||
tcd1.normal_method()
|
||||
tcd1.template_method(0, "hi")
|
||||
tcd1.template_method("hey", "ho")
|
||||
|
||||
# Templated constructors (protected)
|
||||
tcd2 = TemplateConstructor2Derived()
|
||||
tcd2.normal_method()
|
||||
tcd2.template_method(0, "hi")
|
||||
tcd2.template_method("hey", "ho")
|
||||
|
|
|
@ -952,20 +952,42 @@ Allocate():
|
|||
} else if (Equal(nodeType(ns), "constructor") && !GetFlag(n, "usingctor")) {
|
||||
Swig_warning(WARN_PARSE_USING_CONSTRUCTOR, Getfile(n), Getline(n), "Using declaration '%s' for inheriting constructors uses base '%s' which is not an immediate base of '%s'.\n", SwigType_namestr(Getattr(n, "uname")), SwigType_namestr(Getattr(ns, "name")), SwigType_namestr(Getattr(parentNode(n), "name")));
|
||||
} else {
|
||||
String *ntype = nodeType(ns);
|
||||
if (Equal(ntype, "cdecl") || Equal(ntype, "constructor")) {
|
||||
if (inclass && !GetFlag(n, "feature:ignore") && Getattr(n, "sym:name")) {
|
||||
{
|
||||
/* A normal C declaration or constructor declaration
|
||||
* Now add a new class member top the parse tree (copied from the base class member pointed to by the using declaration) */
|
||||
if ((inclass) && (!GetFlag(n, "feature:ignore")) && (Getattr(n, "sym:name"))) {
|
||||
String *ntype = nodeType(ns);
|
||||
if (Equal(ntype, "cdecl") || Equal(ntype, "constructor") || Equal(ntype, "template")) {
|
||||
/* Add a new class member to the parse tree (copy it from the base class member pointed to by the using declaration in node n) */
|
||||
Node *c = ns;
|
||||
Node *unodes = 0, *last_unodes = 0;
|
||||
int ccount = 0;
|
||||
|
||||
while (c) {
|
||||
if (Equal(nodeType(c), ntype)) {
|
||||
String *cnodetype = nodeType(c);
|
||||
if (Equal(cnodetype, "cdecl")) {
|
||||
add_member_for_using_declaration(c, n, ccount, unodes, last_unodes);
|
||||
} else if (Equal(nodeType(c), "using")) {
|
||||
} else if (Equal(cnodetype, "constructor")) {
|
||||
add_member_for_using_declaration(c, n, ccount, unodes, last_unodes);
|
||||
} else if (Equal(cnodetype, "template")) {
|
||||
// A templated member (in a non-template class or in a template class that where the member has a separate template declaration)
|
||||
// Find the template instantiations in the using declaration (base class)
|
||||
for (Node *member = ns; member; member = nextSibling(member)) {
|
||||
/* Constructors have already been handled, only add member functions
|
||||
* This adds an implicit template instantiation and is a bit unusual as SWIG requires explicit %template for other template instantiations.
|
||||
* However, of note, is that there is no valid C++ syntax for a template instantiation to introduce a name via a using declaration...
|
||||
*
|
||||
* struct Base { template <typename T> void template_method(T, T) {} };
|
||||
* struct Derived : Base { using Base::template_method; };
|
||||
* %template() Base::template_method<int>; // SWIG template instantiation
|
||||
* template void Base::template_method<int>(int, int); // C++ template instantiation
|
||||
* template void Derived::template_method<int>(int, int); // Not valid C++
|
||||
*/
|
||||
if (Getattr(member, "template") == ns && checkAttribute(ns, "templatetype", "cdecl")) {
|
||||
if (!GetFlag(member, "feature:ignore") && !Getattr(member, "error")) {
|
||||
add_member_for_using_declaration(member, n, ccount, unodes, last_unodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (Equal(cnodetype, "using")) {
|
||||
for (Node *member = firstChild(c); member; member = nextSibling(member)) {
|
||||
add_member_for_using_declaration(member, n, ccount, unodes, last_unodes);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue