mirror of https://github.com/swig/swig
Partial template specialization fixes to support default arguments
Default argments come from the primary template's parameter list. Example: template<class Y, class T=int> struct X { void primary() {} }; // Previously the specialization below resulted in: // Error: Inconsistent argument count in template partial specialization. 1 2 template<class YY> struct X<YY*> { void special(YY*) {} }; // Both of these correctly wrap the partially specialized template %template(StringPtr) X<const char *>; %template(ShortPtr) X<short *, int>;
This commit is contained in:
parent
a55e429bf2
commit
9924c5c3e1
|
@ -7,6 +7,19 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-03-01: wsfulton
|
||||
Partial template specialization fixes to support default arguments from the primary
|
||||
template's parameter list.
|
||||
|
||||
template<class Y, class T=int> struct X { void primary() {} };
|
||||
// Previously the specialization below resulted in:
|
||||
// Error: Inconsistent argument count in template partial specialization. 1 2
|
||||
template<class YY> struct X<YY*> { void special(YY*) {} };
|
||||
|
||||
// Both of these correctly wrap the partially specialized template
|
||||
%template(StringPtr) X<const char *>;
|
||||
%template(ShortPtr) X<short *, int>;
|
||||
|
||||
2023-02-15: wsfulton
|
||||
#1300 Further partial template specialization fixes.
|
||||
Fixes when templates are used as a template parameter in a partially specialized
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
%module xxx
|
||||
|
||||
template<class Y, class T=int> struct X { void primary() {} };
|
||||
template<class YY> struct X<YY*> { void special(YY*) {} };
|
||||
|
||||
%template(Xbad1) X<>;
|
||||
%template(Xokay1) X<const char *>;
|
||||
%template(Xokay2) X<const short *, int>;
|
||||
%template(Xbad2) X<const char *, int, double>;
|
|
@ -0,0 +1,2 @@
|
|||
cpp_template_partial_specialization_defaults.i:6: Error: Not enough template parameters specified. Minimum of 1 required.
|
||||
cpp_template_partial_specialization_defaults.i:9: Error: Too many template parameters. Maximum of 2.
|
|
@ -0,0 +1,49 @@
|
|||
import template_partial_specialization_more.*;
|
||||
|
||||
public class template_partial_specialization_more_runme {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("template_partial_specialization_more");
|
||||
} 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[]) {
|
||||
// (1)
|
||||
VectInt vi = new VectInt();
|
||||
int num = new FooVectIntDouble().partially_specialized(222);
|
||||
new FooShortPtrDouble().pointer_specialize((short)0);
|
||||
vi = new FooVectVectInt().partially_specialized(vi);
|
||||
|
||||
// (2)
|
||||
new HeyInts().special_hey();
|
||||
|
||||
// (3)
|
||||
new XX1().special1();
|
||||
new XX2().special2();
|
||||
new XX3().special3();
|
||||
|
||||
// (4)
|
||||
new PartiallerPrimary().primary((short)0, (short)0);
|
||||
new PartiallerSpecial().special(new PlainStruct(), 999, true);
|
||||
|
||||
// (5)
|
||||
new LystDouble().primary(11.1, new AllocatorDouble());
|
||||
new LystShort().primary((short)0, new AllocatorShort());
|
||||
new LystPlainStructPtr().specialized1(new PlainStruct(), new AllocatorPlainStructPtr());
|
||||
new LystDoublePtrPtr().specialized2(22.2, (SWIGTYPE_p_p_double)null);
|
||||
new LystConstIntRef().specialized3(100);
|
||||
new LystConstStringRef().specialized3("hello");
|
||||
|
||||
// (6)
|
||||
SpecDoubleInt d = new SpecDoubleInt();
|
||||
SpecStringInt i = new SpecStringInt();
|
||||
d.spec_specialized(12.3);
|
||||
i.spec_specialized("hi");
|
||||
template_partial_specialization_more.UseSpec1(d, d);
|
||||
template_partial_specialization_more.UseSpec2(i, i);
|
||||
}
|
||||
}
|
|
@ -72,32 +72,70 @@ template<typename S1, typename S2> struct Partialler<S2, S1*> { void special(S1*
|
|||
|
||||
|
||||
// (5) Default args used in specialization, like std::list
|
||||
%include <std_string.i>
|
||||
%inline %{
|
||||
template <typename A> struct Allocator {};
|
||||
template <typename T, class Alloc = Allocator<T> > struct Lyst { void primary(T, Allocator<T>) {} };
|
||||
template <typename TT, class XXAlloc> struct Lyst<TT*, XXAlloc> { void specialized1(TT, XXAlloc) {} };
|
||||
template <typename TTT, class YY> struct Lyst<TTT**, Allocator<YY> > { void specialized2(TTT, YY) {} };
|
||||
// TODO Error: Inconsistent argument count in template partial specialization. 1 2
|
||||
//template <typename TTTT> struct Lyst<const TTTT&> { void specialized3(TTTT) {} };
|
||||
template <typename TTTT> struct Lyst<const TTTT&> { void specialized3(TTTT) {} };
|
||||
|
||||
void test_list() {
|
||||
int myint = 0;
|
||||
Lyst<int> lis;
|
||||
lis.primary(myint, Allocator<int>());
|
||||
double mydouble = 0;
|
||||
Lyst<double>().primary(mydouble, Allocator<double>());
|
||||
Lyst<short, Allocator<short> >().primary(mydouble, Allocator<short>());
|
||||
|
||||
PlainStruct ps;
|
||||
Lyst<PlainStruct *> liss;
|
||||
liss.specialized1(ps, Allocator<PlainStruct *>());
|
||||
|
||||
double mydouble = 0;
|
||||
Lyst<double **> lissd;
|
||||
lissd.specialized2(mydouble, (double **)0);
|
||||
|
||||
// Lyst<const int&> lissconstint;
|
||||
// lissconstint.specialized3(myint);
|
||||
int myint = 0;
|
||||
std::string mystring = 0;
|
||||
Lyst<PlainStruct *>().specialized1(ps, Allocator<PlainStruct *>());
|
||||
Lyst<double **>().specialized2(mydouble, (double **)0);
|
||||
Lyst<const int&>().specialized3(myint);
|
||||
// Specifying the default still calls the partially specialized template
|
||||
Lyst<std::string const &, Allocator<std::string const &> >().specialized3(mystring);
|
||||
}
|
||||
%}
|
||||
|
||||
%template(AllocatorDouble) Allocator<double>;
|
||||
%template(AllocatorShort) Allocator<short>;
|
||||
%template(AllocatorPlainStructPtr) Allocator<PlainStruct *>;
|
||||
|
||||
%template(LystDouble) Lyst<double>;
|
||||
//%template(LystDouble) Lyst<short, Allocator<short> >;
|
||||
%template(LystShort) Lyst<short, Allocator<short> >;
|
||||
%template(LystPlainStructPtr) Lyst<PlainStruct *>;
|
||||
%template(LystDoublePtrPtr) Lyst<double **>; // called specialized1 instead of specialized2
|
||||
%template(LystConstIntRef) Lyst<const int&>;
|
||||
%template(LystConstStringRef) Lyst<const std::string&, Allocator<const std::string&> >;
|
||||
|
||||
%inline %{
|
||||
// Both parameters in each of the functions below are the same type
|
||||
void UseLystDouble(Lyst<double> a, Lyst<double, Allocator<double> > b) {}
|
||||
void UseLystShort(Lyst<short> a, Lyst<short, Allocator<short> > b) {}
|
||||
void UseLystPlainStructPtr(Lyst<PlainStruct *> a, Lyst<PlainStruct *, Allocator<PlainStruct *> > b) {}
|
||||
void UseLystDoublePtrPtr(Lyst<double **> a, Lyst<double **, Allocator<double **> > b) {}
|
||||
void UseLystConstIntRef(Lyst<const int&> a, Lyst<const int&, Allocator<const int&> > b) {}
|
||||
void UseLystConstStringRef(Lyst<const std::string&> a, Lyst<const std::string&, Allocator<const std::string&> > b) {}
|
||||
%}
|
||||
|
||||
// (6) Default args used in specialization, more variations specifying / not specifying default
|
||||
%inline %{
|
||||
template<typename P, typename Q = int> struct Spec { void spec_primary(P p, Q q) {} };
|
||||
template<typename PP> struct Spec<const PP&, int> { void spec_specialized(PP pp) {} };
|
||||
%}
|
||||
|
||||
%template(SpecDoubleInt) Spec<const double&, int>;
|
||||
%template(SpecStringInt) Spec<const std::string&>;
|
||||
|
||||
%inline %{
|
||||
void UseSpec1(Spec<const double&, int> x, Spec<const double&, int> y) {}
|
||||
void UseSpec2(Spec<const std::string&, int> x, Spec<const std::string&, int> y) {}
|
||||
void test_spec() {
|
||||
double mydouble = 0.0;
|
||||
Spec<const double&, int>().spec_specialized(mydouble);
|
||||
Spec<const double&>().spec_specialized(mydouble);
|
||||
|
||||
std::string mystring;
|
||||
Spec<const std::string&, int>().spec_specialized(mystring);
|
||||
Spec<const std::string&>().spec_specialized(mystring);
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -69,6 +69,7 @@ extern "C" {
|
|||
extern Node *Swig_cparse_template_locate(String *name, ParmList *tparms, String *symname, Symtab *tscope);
|
||||
extern void Swig_cparse_debug_templates(int);
|
||||
extern ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary, Node *templ);
|
||||
extern ParmList *Swig_cparse_template_partialargs_expand(ParmList *partially_specialized_parms, Node *primary, ParmList *templateparms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -4121,10 +4121,10 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN {
|
|||
set_nodeType($$,"template");
|
||||
/* Template partial specialization */
|
||||
if (tempn && ($3) && ($6)) {
|
||||
List *tlist;
|
||||
String *targs = SwigType_templateargs(tname);
|
||||
tlist = SwigType_parmlist(targs);
|
||||
/* Printf(stdout,"targs = '%s' %s\n", targs, tlist); */
|
||||
ParmList *primary_templateparms = Getattr(tempn, "templateparms");
|
||||
String *targs = SwigType_templateargs(tname); /* tname contains name and specialized template parameters, for example: X<(p.T,TT)> */
|
||||
List *tlist = SwigType_parmlist(targs);
|
||||
int specialization_parms_len = Len(tlist);
|
||||
if (!Getattr($$,"sym:weak")) {
|
||||
Setattr($$,"sym:typename","1");
|
||||
}
|
||||
|
@ -4133,13 +4133,15 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN {
|
|||
Delattr($$, "specialization");
|
||||
Setattr($$, "partialspecialization", "1");
|
||||
|
||||
if (Len(tlist) != ParmList_len(Getattr(tempn,"templateparms"))) {
|
||||
Swig_error(Getfile($$),Getline($$),"Inconsistent argument count in template partial specialization. %d %d\n", Len(tlist), ParmList_len(Getattr(tempn,"templateparms")));
|
||||
if (specialization_parms_len > ParmList_len(primary_templateparms)) {
|
||||
Swig_error(Getfile($$), Getline($$), "Template partial specialization has more arguments than primary template %d %d.\n", specialization_parms_len, ParmList_len(primary_templateparms));
|
||||
|
||||
} else if (specialization_parms_len < ParmList_numrequired(primary_templateparms)) {
|
||||
Swig_error(Getfile($$), Getline($$), "Template partial specialization has fewer arguments than primary template %d %d.\n", specialization_parms_len, ParmList_len(primary_templateparms));
|
||||
} else {
|
||||
/* Create a specialized name with template parameters replaced with $ variables, such as, X<(T1,p.T2) => X<($1,p.$2)> */
|
||||
Parm *p = $3;
|
||||
String *fname = NewString(Getattr($$,"name"));
|
||||
String *fname = NewString(tname);
|
||||
String *ffname = 0;
|
||||
ParmList *partialparms = 0;
|
||||
|
||||
|
@ -4183,6 +4185,27 @@ cpp_template_decl : TEMPLATE LESSTHAN template_parms GREATERTHAN {
|
|||
Delete(tparms);
|
||||
Append(ffname,")>");
|
||||
}
|
||||
{
|
||||
/* Replace each primary template parameter's name and value with $ variables, such as, class Y,class T=Y => class $1,class $2=$1 */
|
||||
ParmList *primary_templateparms_copy = CopyParmList(primary_templateparms);
|
||||
p = primary_templateparms_copy;
|
||||
i = 0;
|
||||
while (p) {
|
||||
String *name = Getattr(p, "name");
|
||||
Parm *pp = nextSibling(p);
|
||||
++i;
|
||||
sprintf(tmp, "$%d", i);
|
||||
while (pp) {
|
||||
Replaceid(Getattr(pp, "value"), name, tmp);
|
||||
pp = nextSibling(pp);
|
||||
}
|
||||
Setattr(p, "name", NewString(tmp));
|
||||
p = nextSibling(p);
|
||||
}
|
||||
/* Modify partialparms by adding in missing default values ($ variables) from primary template parameters */
|
||||
partialparms = Swig_cparse_template_partialargs_expand(partialparms, tempn, primary_templateparms_copy);
|
||||
Delete(primary_templateparms_copy);
|
||||
}
|
||||
{
|
||||
Node *new_partial = NewHash();
|
||||
String *partials = Getattr(tempn,"partials");
|
||||
|
|
|
@ -498,7 +498,6 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
|
|||
p = nextSibling(p);
|
||||
tp = nextSibling(tp);
|
||||
}
|
||||
assert(ParmList_len(ptargs) == ParmList_len(tparms));
|
||||
Delete(ptargs);
|
||||
} else {
|
||||
Setattr(n, "templateparmsraw", Getattr(n, "templateparms"));
|
||||
|
@ -835,7 +834,7 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
|
|||
targs = Getattr(templ, "templateparms");
|
||||
expandedparms = Swig_symbol_template_defargs(parms, targs, tscope, primary_scope);
|
||||
|
||||
/* reduce the typedef */
|
||||
/* Qualify template parameters */
|
||||
p = expandedparms;
|
||||
while (p) {
|
||||
SwigType *ty = Getattr(p, "type");
|
||||
|
@ -934,14 +933,13 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
|
|||
partials = Getattr(templ, "partials"); /* note that these partial specializations do not include explicit specializations */
|
||||
if (partials) {
|
||||
Iterator pi;
|
||||
int parms_len = ParmList_len(parms);
|
||||
int parms_len = ParmList_len(parms); /* max parameters including defaulted parameters from primary template (ie max parameters) */
|
||||
int *priorities_row;
|
||||
max_possible_partials = Len(partials);
|
||||
priorities_matrix = (int *)Malloc(sizeof(int) * max_possible_partials * parms_len); /* slightly wasteful allocation for max possible matches */
|
||||
priorities_row = priorities_matrix;
|
||||
for (pi = First(partials); pi.item; pi = Next(pi)) {
|
||||
Parm *p = parms;
|
||||
int all_parameters_match = 1;
|
||||
int i = 1;
|
||||
Parm *partialparms = Getattr(pi.item, "partialparms");
|
||||
Parm *pp = partialparms;
|
||||
|
@ -950,6 +948,7 @@ static Node *template_locate(String *name, Parm *instantiated_parms, String *sym
|
|||
Printf(stdout, " checking match: '%s' (partial specialization)\n", templcsymname);
|
||||
}
|
||||
if (ParmList_len(partialparms) == parms_len) {
|
||||
int all_parameters_match = 1;
|
||||
while (p && pp) {
|
||||
SwigType *t;
|
||||
t = Getattr(p, "type");
|
||||
|
@ -1165,15 +1164,18 @@ Node *Swig_cparse_template_locate(String *name, Parm *instantiated_parms, String
|
|||
Parm *tparmsfound = Getattr(primary ? primary : n, "templateparms");
|
||||
int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */
|
||||
int variadic = ParmList_variadic_parm(tparmsfound) != 0;
|
||||
match = n;
|
||||
if (!specialized) {
|
||||
if (!variadic && (ParmList_len(instantiated_parms) > ParmList_len(tparmsfound))) {
|
||||
Swig_error(cparse_file, cparse_line, "Too many template parameters. Maximum of %d.\n", ParmList_len(tparmsfound));
|
||||
match = 0;
|
||||
} else if (ParmList_len(instantiated_parms) < ParmList_numrequired(tparmsfound) - (variadic ? 1 : 0)) { /* Variadic parameter is optional */
|
||||
Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", (ParmList_numrequired(tparmsfound) - (variadic ? 1 : 0)) );
|
||||
Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. Minimum of %d required.\n", (ParmList_numrequired(tparmsfound) - (variadic ? 1 : 0)) );
|
||||
match = 0;
|
||||
}
|
||||
}
|
||||
SetFlag(n, "instantiate");
|
||||
match = n;
|
||||
if (match)
|
||||
SetFlag(n, "instantiate");
|
||||
} else {
|
||||
Node *firstn = 0;
|
||||
/* If not a templated class we must have a templated function.
|
||||
|
@ -1285,6 +1287,22 @@ static void use_mark_defaults(ParmList *defaults) {
|
|||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* use_mark_specialized_defaults()
|
||||
*
|
||||
* Modify extra defaulted parameters ready for adding to specialized template parameters list
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
static void use_mark_specialized_defaults(ParmList *defaults) {
|
||||
Parm *tp = defaults;
|
||||
while (tp) {
|
||||
Setattr(tp, "default", "1");
|
||||
Setattr(tp, "type", Getattr(tp, "value"));
|
||||
Delattr(tp, "name");
|
||||
tp = nextSibling(tp);
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* expand_defaults()
|
||||
*
|
||||
|
@ -1324,12 +1342,11 @@ static void expand_defaults(ParmList *expanded_templateparms) {
|
|||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary, Node *templ) {
|
||||
ParmList *expanded_templateparms = 0;
|
||||
ParmList *expanded_templateparms = CopyParmList(instantiated_parms);
|
||||
|
||||
if (Equal(Getattr(primary, "templatetype"), "class")) {
|
||||
/* Templated class */
|
||||
ParmList *templateparms = Getattr(primary, "templateparms");
|
||||
expanded_templateparms = CopyParmList(instantiated_parms);
|
||||
int variadic = merge_parameters(expanded_templateparms, templateparms);
|
||||
/* Add default arguments from primary template */
|
||||
if (!variadic) {
|
||||
|
@ -1345,9 +1362,43 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *
|
|||
/* Templated function */
|
||||
/* TODO: Default template parameters support was only added in C++11 */
|
||||
ParmList *templateparms = Getattr(templ, "templateparms");
|
||||
expanded_templateparms = CopyParmList(instantiated_parms);
|
||||
merge_parameters(expanded_templateparms, templateparms);
|
||||
}
|
||||
|
||||
return expanded_templateparms;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Swig_cparse_template_partialargs_expand()
|
||||
*
|
||||
* partially_specialized_parms: partially specialized template parameters
|
||||
* primary: primary template node
|
||||
* templateparms: primary template parameters (providing the defaults)
|
||||
*
|
||||
* Expand the partially_specialized_parms and return a parameter list with default
|
||||
* arguments filled in where necessary.
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
ParmList *Swig_cparse_template_partialargs_expand(ParmList *partially_specialized_parms, Node *primary, ParmList *templateparms) {
|
||||
ParmList *expanded_templateparms = CopyParmList(partially_specialized_parms);
|
||||
|
||||
if (Equal(Getattr(primary, "templatetype"), "class")) {
|
||||
/* Templated class */
|
||||
int variadic = ParmList_variadic_parm(templateparms) ? 1 : 0;
|
||||
/* Add default arguments from primary template */
|
||||
if (!variadic) {
|
||||
ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(partially_specialized_parms));
|
||||
if (defaults_start) {
|
||||
ParmList *defaults = CopyParmList(defaults_start);
|
||||
use_mark_specialized_defaults(defaults);
|
||||
expanded_templateparms = ParmList_join(expanded_templateparms, defaults);
|
||||
expand_defaults(expanded_templateparms);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Templated function */
|
||||
/* TODO: Default template parameters support was only added in C++11 */
|
||||
}
|
||||
|
||||
return expanded_templateparms;
|
||||
}
|
||||
|
|
|
@ -190,7 +190,8 @@ Parm *ParmList_variadic_parm(ParmList *p) {
|
|||
/* -----------------------------------------------------------------------------
|
||||
* ParmList_numrequired()
|
||||
*
|
||||
* Return number of required arguments
|
||||
* Return number of required arguments - the number of arguments excluding
|
||||
* default arguments
|
||||
* ----------------------------------------------------------------------------- */
|
||||
|
||||
int ParmList_numrequired(ParmList *p) {
|
||||
|
|
Loading…
Reference in New Issue