diff --git a/Examples/test-suite/java/template_templated_constructors_runme.java b/Examples/test-suite/java/template_templated_constructors_runme.java index cd3f31d21..ec20b9486 100644 --- a/Examples/test-suite/java/template_templated_constructors_runme.java +++ b/Examples/test-suite/java/template_templated_constructors_runme.java @@ -21,6 +21,16 @@ public class template_templated_constructors_runme { TClass2Int tc2a = new TClass2Int(); TClass2Int tc2b = new TClass2Int(123.4); + DoublePair double_pair = new DoublePair(1.1, 2.2); + ShortPair short_pair = new ShortPair((short)0, (short)1); + StringPair string_pair = new StringPair("10", "11"); + IntPair ip1 = new IntPair(); + IntPair ip2 = new IntPair(20, 21); + IntPair ip3 = new IntPair(ip1); + IntPair ip4 = new IntPair(short_pair); + // These next two use IntPair constructors, unlike Python which requires factory function calls + IntPair ip5 = new IntPair(double_pair); + IntPair ip6 = new IntPair(string_pair); } } diff --git a/Examples/test-suite/python/template_templated_constructors_runme.py b/Examples/test-suite/python/template_templated_constructors_runme.py new file mode 100644 index 000000000..c3fbda0cd --- /dev/null +++ b/Examples/test-suite/python/template_templated_constructors_runme.py @@ -0,0 +1,20 @@ +from template_templated_constructors import * + +t1 = TConstructor1(123) +t2a = TConstructor2() +t2b = TConstructor2(123) + +tc1 = TClass1Int(123.4) +tc2a = TClass2Int() +tc2b = TClass2Int(123.4) + +double_pair = DoublePair(1.1, 2.2) +short_pair = ShortPair(0, 1) +string_pair = StringPair("10", "11") +ip1 = IntPair() +ip2 = IntPair(20, 21) +ip3 = IntPair(ip1) +ip4 = IntPair(short_pair) +# These next two create an IntPair from factory function calls in Python, unlike Java which calls the IntPair constructor +ip5 = Pair(double_pair) +ip6 = MakeStringPair(string_pair) diff --git a/Examples/test-suite/template_templated_constructors.i b/Examples/test-suite/template_templated_constructors.i index 409ff1cf7..c7f92ef43 100644 --- a/Examples/test-suite/template_templated_constructors.i +++ b/Examples/test-suite/template_templated_constructors.i @@ -59,3 +59,37 @@ public: %extend ConstructSpace::TClass2 { %template(TClass2Int) TClass2; } + +%inline %{ +// Simple version of std::pair +namespace Standard { + template struct Pair { + typedef T first_type; + typedef U second_type; + Pair() {} + Pair(const T& first, const U& second) {} + Pair(const Pair& other) {} + + template Pair(const Pair< U1, U2 > &otherone) {} + }; +} +%} + +%include + +namespace Standard { + %template(StringPair) Pair; + %template(ShortPair) Pair; + %template(IntPair) Pair; + %template(DoublePair) Pair; + %extend Pair { + // Templated constructor which uses 'correct' name of the containing class (IntPair) + %template(IntPair) Pair; + // Templated constructors that behave differently in different languages as the template name + // does not match IntPair, the instantiated name for Pair. + // Some languages wrap as a factory style function (Python), + // others ignore the name and wrap as regular constructor (Java). + %template(Pair) Pair; + %template(MakeStringPair) Pair; + } +} diff --git a/Source/CParse/templ.c b/Source/CParse/templ.c index c4577aa6c..d979e6bb3 100644 --- a/Source/CParse/templ.c +++ b/Source/CParse/templ.c @@ -224,25 +224,16 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri } } } else if (Equal(nodeType, "constructor")) { - String *name = Getattr(n, "name"); if (!(Getattr(n, "templatetype"))) { - String *symname; - String *stripped_name = SwigType_templateprefix(name); - if (Strstr(tname, stripped_name)) { - Replaceid(name, stripped_name, tname); - } - Delete(stripped_name); - symname = Getattr(n, "sym:name"); + String *symname = Getattr(n, "sym:name"); + String *name; if (symname) { - stripped_name = SwigType_templateprefix(symname); + String *stripped_name = SwigType_templateprefix(symname); if (Strstr(tname, stripped_name)) { Replaceid(symname, stripped_name, tname); } Delete(stripped_name); } - if (strchr(Char(name), '<')) { - Append(patchlist, Getattr(n, "name")); - } name = Getattr(n, "sym:name"); if (name) { if (strchr(Char(name), '<')) { @@ -266,21 +257,9 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri * template node, with the special exception for %extend which adds its methods under an intermediate node. */ Node* parent = parentNode(n); if (parent == templnode || (parentNode(parent) == templnode && Equal(nodeType(parent), "extend"))) { - String *name = Getattr(n, "name"); - if (name) { - if (strchr(Char(name), '<')) - Append(patchlist, Getattr(n, "name")); - } - name = Getattr(n, "sym:name"); - if (name) { - if (strchr(Char(name), '<')) { - String *sn = Copy(tname); - Setattr(n, "sym:name", sn); - Delete(sn); - } else { - Replace(name, tname, rname, DOH_REPLACE_ANY); - } - } + String *symname = Getattr(n, "sym:name"); + if (symname) + Replace(symname, tname, rname, DOH_REPLACE_ANY); Append(cpatchlist, Getattr(n, "code")); } } else if (Equal(nodeType, "using")) { @@ -478,7 +457,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab List *patchlist, *cpatchlist, *typelist; String *templateargs; String *tname; - String *iname; + String *name_with_templateargs = 0; String *tbase; Parm *unexpanded_variadic_parm = 0; ParmList *expanded_variadic_parms = 0; @@ -551,9 +530,12 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab { String *name = Getattr(n, "name"); if (name) { - Append(name, templateargs); + String *nodeType = nodeType(n); + name_with_templateargs = NewStringf("%s%s", name, templateargs); + if (!(Equal(nodeType, "constructor") || Equal(nodeType, "destructor"))) { + Setattr(n, "name", name_with_templateargs); + } } - iname = name; } /* Patch all of the types */ @@ -609,12 +591,12 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab Node *tynode = Swig_symbol_clookup(s, 0); String *tyname = tynode ? Getattr(tynode, "sym:name") : 0; /* - Printf(stdout, " replacing %s with %s to %s or %s to %s\n", s, name, dvalue, tbase, iname); + Printf(stdout, " replacing %s with %s to %s or %s to %s\n", s, name, dvalue, tbase, name_with_templateargs); Printf(stdout, " %d %s to %s\n", tp == unexpanded_variadic_parm, name, ParmList_str_defaultargs(expanded_variadic_parms)); */ if (!tyname || !tsname || !Equal(tyname, tsname) || Getattr(tynode, "templatetype")) { SwigType_typename_replace(s, name, dvalue); - SwigType_typename_replace(s, tbase, iname); + SwigType_typename_replace(s, tbase, name_with_templateargs); } } @@ -645,7 +627,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab String *s = Getitem(typelist, i); assert(!SwigType_isvariadic(s)); /* All parameters should have already been expanded, this is for function that contain variadic parameters only, such as f(v.p.V) */ SwigType_variadic_replace(s, unexpanded_variadic_parm, expanded_variadic_parms); - SwigType_typename_replace(s, tbase, iname); + SwigType_typename_replace(s, tbase, name_with_templateargs); } } } @@ -664,6 +646,7 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab } } } + Delete(name_with_templateargs); Delete(patchlist); Delete(cpatchlist); Delete(typelist); @@ -671,7 +654,6 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab Delete(tname); Delete(templateargs); - /* set_nodeType(n,"template"); */ return 0; } diff --git a/Source/Modules/lang.cxx b/Source/Modules/lang.cxx index 63d7f4963..ac3c8aa07 100644 --- a/Source/Modules/lang.cxx +++ b/Source/Modules/lang.cxx @@ -2555,13 +2555,18 @@ int Language::constructorDeclaration(Node *n) { return SWIG_NOWRAP; } - /* Name adjustment for %rename */ + // Name adjustment of constructor when a class has been renamed with %rename Swig_save("constructorDeclaration", n, "sym:name", NIL); { String *base = Swig_scopename_last(name); - if ((Strcmp(base, symname) == 0) && (Strcmp(symname, ClassPrefix) != 0)) { - Setattr(n, "sym:name", ClassPrefix); + // Note that it is possible for the constructor to have a different name to the class name in + // some target languages, where it is wrapped as a factory type function instead of a constructor. + if (Equal(base, symname) && !Equal(symname, ClassPrefix)) { + // Adjust name, except when the constructor's name comes from a templated constructor, + // where the name passed to %template is used instead. + if (!Getattr(n, "template")) + Setattr(n, "sym:name", ClassPrefix); } Delete(base); }