mirror of https://github.com/swig/swig
Instantiation of C++11 variadic function templates
Complete support for C++11 variadic function templates. Support was previously limited to just one template parameter. Now zero or more template parameters are supported in the %template instantiation.
This commit is contained in:
parent
cdc08c9325
commit
2fc0edc4fd
|
@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
||||||
Version 4.2.0 (in progress)
|
Version 4.2.0 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2023-01-03: wsfulton
|
||||||
|
Complete support for C++11 variadic function templates. Support was previously limited
|
||||||
|
to just one template parameter. Now zero or more template parameters are supported
|
||||||
|
in the %template instantiation.
|
||||||
|
|
||||||
2022-12-29: wsfulton
|
2022-12-29: wsfulton
|
||||||
#1863 Syntax error fixes parsing more elaborate parameter pack arguments that are
|
#1863 Syntax error fixes parsing more elaborate parameter pack arguments that are
|
||||||
used in function pointers, member function pointers:
|
used in function pointers, member function pointers:
|
||||||
|
@ -50,7 +55,7 @@ Version 4.2.0 (in progress)
|
||||||
are function pointers.
|
are function pointers.
|
||||||
|
|
||||||
2022-12-22: wsfulton
|
2022-12-22: wsfulton
|
||||||
Complete support for C++11 variadic templates. Support was previously limited
|
Complete support for C++11 variadic class templates. Support was previously limited
|
||||||
to just one template parameter. Now zero or more template parameters are supported.
|
to just one template parameter. Now zero or more template parameters are supported.
|
||||||
|
|
||||||
2022-12-06: wsfulton
|
2022-12-06: wsfulton
|
||||||
|
|
|
@ -78,5 +78,19 @@ void emplace(Args &&... args) noexcept(
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%template(emplace) EmplaceContainer::emplace<int,A>;
|
%template(emplace) EmplaceContainer::emplace<int,A>;
|
||||||
// TODO
|
%template(emplace) EmplaceContainer::emplace<int,A,B>;
|
||||||
//%template(emplace) EmplaceContainer::emplace<int,A,B,C>;
|
%template(emplace) EmplaceContainer::emplace<int,A,B,C>;
|
||||||
|
%template(emplace) EmplaceContainer::emplace<int,A,B,C,D>;
|
||||||
|
|
||||||
|
|
||||||
|
// Overloading mix of variadic and non-variadic templates
|
||||||
|
%inline %{
|
||||||
|
template<typename T, typename U> int variadicmix1(T t, U u) { return 10; }
|
||||||
|
template<typename... T> int variadicmix1(T... t) { return 20; }
|
||||||
|
%}
|
||||||
|
|
||||||
|
%template(variadicmix1) variadicmix1<>;
|
||||||
|
%template(variadicmix1) variadicmix1<A>;
|
||||||
|
%template(variadicmix1) variadicmix1<A,B>;
|
||||||
|
%template(variadicmix1) variadicmix1<A,B,C>;
|
||||||
|
%template(variadicmix1) variadicmix1<int, int>;
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
from cpp11_variadic_function_templates import *
|
||||||
|
|
||||||
|
ec = EmplaceContainer()
|
||||||
|
ec.emplace(A())
|
||||||
|
ec.emplace(A(), B())
|
||||||
|
ec.emplace(A(), B(), C())
|
||||||
|
ec.emplace(A(), B(), C(), D())
|
||||||
|
|
||||||
|
def check(expected, got):
|
||||||
|
if expected != got:
|
||||||
|
raise RuntimeError("failed: {} != {}".format(expected, got))
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
b = B()
|
||||||
|
c = C()
|
||||||
|
check(variadicmix1(), 20)
|
||||||
|
check(variadicmix1(a), 20)
|
||||||
|
check(variadicmix1(a, b), 10)
|
||||||
|
check(variadicmix1(a, b, c), 20)
|
||||||
|
check(variadicmix1(11, 22), 10)
|
|
@ -2817,8 +2817,6 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
|
||||||
Node *n;
|
Node *n;
|
||||||
Node *outer_class = currentOuterClass;
|
Node *outer_class = currentOuterClass;
|
||||||
Symtab *tscope = 0;
|
Symtab *tscope = 0;
|
||||||
int specialized = 0; /* fully specialized (an explicit specialization) */
|
|
||||||
int variadic = 0;
|
|
||||||
String *symname = $3 ? NewString($3) : 0;
|
String *symname = $3 ? NewString($3) : 0;
|
||||||
|
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
|
@ -2875,23 +2873,12 @@ template_directive: SWIGTEMPLATE LPAREN idstringopt RPAREN idcolonnt LESSTHAN va
|
||||||
Node *linkliststart = 0;
|
Node *linkliststart = 0;
|
||||||
while (nn) {
|
while (nn) {
|
||||||
Node *templnode = 0;
|
Node *templnode = 0;
|
||||||
if (Strcmp(nodeType(nn),"template") == 0) {
|
if (GetFlag(nn, "instantiate")) {
|
||||||
int nnisclass = (Strcmp(Getattr(nn,"templatetype"),"class") == 0); /* if not a templated class it is a templated function */
|
Delattr(nn, "instantiate");
|
||||||
Parm *tparms = Getattr(nn,"templateparms");
|
{
|
||||||
if (!tparms) {
|
int nnisclass = (Strcmp(Getattr(nn, "templatetype"), "class") == 0); /* if not a templated class it is a templated function */
|
||||||
specialized = 1;
|
Parm *tparms = Getattr(nn, "templateparms");
|
||||||
} else if (ParmList_variadic_parm(tparms)) {
|
int specialized = !tparms; /* fully specialized (an explicit specialization) */
|
||||||
variadic = 1;
|
|
||||||
}
|
|
||||||
if (nnisclass && !variadic && !specialized && (ParmList_len($7) > ParmList_len(tparms))) {
|
|
||||||
Swig_error(cparse_file, cparse_line, "Too many template parameters. Maximum of %d.\n", ParmList_len(tparms));
|
|
||||||
} else if (nnisclass && !specialized && ((ParmList_len($7) < (ParmList_numrequired(tparms) - (variadic?1:0))))) { /* Variadic parameter is optional */
|
|
||||||
Swig_error(cparse_file, cparse_line, "Not enough template parameters specified. %d required.\n", (ParmList_numrequired(tparms)-(variadic?1:0)) );
|
|
||||||
} else if (!nnisclass && ((ParmList_len($7) != ParmList_len(tparms)))) {
|
|
||||||
/* must be an overloaded templated method - ignore it as it is overloaded with a different number of template parameters */
|
|
||||||
nn = Getattr(nn,"sym:nextSibling"); /* repeat for overloaded templated functions */
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
String *tname = Copy($5);
|
String *tname = Copy($5);
|
||||||
Node *primary_template = Swig_symbol_clookup(tname, 0);
|
Node *primary_template = Swig_symbol_clookup(tname, 0);
|
||||||
|
|
||||||
|
|
|
@ -691,7 +691,7 @@ static EMatch does_parm_match(SwigType *type, SwigType *partial_parm_type, const
|
||||||
* Search for a template that matches name with given parameters.
|
* Search for a template that matches name with given parameters.
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static Node *template_locate(String *name, Parm *tparms, String *symname, Symtab *tscope) {
|
static Node *template_locate(String *name, Parm *instantiated_parms, String *symname, Symtab *tscope) {
|
||||||
Node *n = 0;
|
Node *n = 0;
|
||||||
String *tname = 0;
|
String *tname = 0;
|
||||||
Node *templ;
|
Node *templ;
|
||||||
|
@ -705,12 +705,9 @@ static Node *template_locate(String *name, Parm *tparms, String *symname, Symtab
|
||||||
int max_possible_partials = 0;
|
int max_possible_partials = 0;
|
||||||
int posslen = 0;
|
int posslen = 0;
|
||||||
|
|
||||||
/* Search for primary (unspecialized) template */
|
|
||||||
templ = Swig_symbol_clookup(name, 0);
|
|
||||||
|
|
||||||
if (template_debug) {
|
if (template_debug) {
|
||||||
tname = Copy(name);
|
tname = Copy(name);
|
||||||
SwigType_add_template(tname, tparms);
|
SwigType_add_template(tname, instantiated_parms);
|
||||||
Printf(stdout, "\n");
|
Printf(stdout, "\n");
|
||||||
if (symname)
|
if (symname)
|
||||||
Swig_diagnostic(cparse_file, cparse_line, "Template debug: Searching for match to: '%s' for instantiation of template named '%s'\n", tname, symname);
|
Swig_diagnostic(cparse_file, cparse_line, "Template debug: Searching for match to: '%s' for instantiation of template named '%s'\n", tname, symname);
|
||||||
|
@ -720,9 +717,16 @@ static Node *template_locate(String *name, Parm *tparms, String *symname, Symtab
|
||||||
tname = 0;
|
tname = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search for primary (unspecialized) template */
|
||||||
|
templ = Swig_symbol_clookup(name, 0);
|
||||||
|
|
||||||
if (templ) {
|
if (templ) {
|
||||||
|
if (template_debug) {
|
||||||
|
Printf(stdout, " found primary template <%s> '%s'\n", ParmList_str_defaultargs(Getattr(templ, "templateparms")), Getattr(templ, "name"));
|
||||||
|
}
|
||||||
|
|
||||||
tname = Copy(name);
|
tname = Copy(name);
|
||||||
parms = CopyParmList(tparms);
|
parms = CopyParmList(instantiated_parms);
|
||||||
|
|
||||||
/* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */
|
/* All template specializations must be in the primary template's scope, store the symbol table for this scope for specialization lookups */
|
||||||
primary_scope = Getattr(templ, "sym:symtab");
|
primary_scope = Getattr(templ, "sym:symtab");
|
||||||
|
@ -788,7 +792,7 @@ static Node *template_locate(String *name, Parm *tparms, String *symname, Symtab
|
||||||
String *previous_name = Getattr(previous_named_instantiation, "name");
|
String *previous_name = Getattr(previous_named_instantiation, "name");
|
||||||
String *previous_symname = Getattr(previous_named_instantiation, "sym:name");
|
String *previous_symname = Getattr(previous_named_instantiation, "sym:name");
|
||||||
String *unprocessed_tname = Copy(name);
|
String *unprocessed_tname = Copy(name);
|
||||||
SwigType_add_template(unprocessed_tname, tparms);
|
SwigType_add_template(unprocessed_tname, instantiated_parms);
|
||||||
|
|
||||||
if (template_debug)
|
if (template_debug)
|
||||||
Printf(stdout, " previous instantiation with name '%s' found: '%s' - duplicate instantiation ignored\n", previous_symname, Getattr(n, "name"));
|
Printf(stdout, " previous instantiation with name '%s' found: '%s' - duplicate instantiation ignored\n", previous_symname, Getattr(n, "name"));
|
||||||
|
@ -1040,14 +1044,15 @@ success:
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* Swig_cparse_template_locate()
|
* Swig_cparse_template_locate()
|
||||||
*
|
*
|
||||||
* Search for a template that matches name with given parameters.
|
* Search for a template that matches name with given parameters and mark it for instantiation.
|
||||||
* For templated classes finds the specialized template should there be one.
|
* For templated classes marks the specialized template should there be one.
|
||||||
* For templated functions finds the unspecialized template even if a specialized
|
* For templated functions marks all the unspecialized templates even if specialized
|
||||||
* template exists.
|
* templates exists.
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
Node *Swig_cparse_template_locate(String *name, Parm *tparms, String *symname, Symtab *tscope) {
|
Node *Swig_cparse_template_locate(String *name, Parm *instantiated_parms, String *symname, Symtab *tscope) {
|
||||||
Node *n = template_locate(name, tparms, symname, tscope); /* this function does what we want for templated classes */
|
Node *match = 0;
|
||||||
|
Node *n = template_locate(name, instantiated_parms, symname, tscope); /* this function does what we want for templated classes */
|
||||||
|
|
||||||
if (n) {
|
if (n) {
|
||||||
String *nodeType = nodeType(n);
|
String *nodeType = nodeType(n);
|
||||||
|
@ -1055,7 +1060,22 @@ Node *Swig_cparse_template_locate(String *name, Parm *tparms, String *symname, S
|
||||||
assert(Equal(nodeType, "template"));
|
assert(Equal(nodeType, "template"));
|
||||||
(void)nodeType;
|
(void)nodeType;
|
||||||
isclass = (Equal(Getattr(n, "templatetype"), "class"));
|
isclass = (Equal(Getattr(n, "templatetype"), "class"));
|
||||||
if (!isclass) {
|
|
||||||
|
if (isclass) {
|
||||||
|
Parm *tparmsfound = Getattr(n, "templateparms");
|
||||||
|
int specialized = !tparmsfound; /* fully specialized (an explicit specialization) */
|
||||||
|
int variadic = ParmList_variadic_parm(tparmsfound) != 0;
|
||||||
|
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));
|
||||||
|
} 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)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetFlag(n, "instantiate");
|
||||||
|
match = n;
|
||||||
|
} else {
|
||||||
|
Node *firstn = 0;
|
||||||
/* If not a templated class we must have a templated function.
|
/* If not a templated class we must have a templated function.
|
||||||
The template found is not necessarily the one we want when dealing with templated
|
The template found is not necessarily the one we want when dealing with templated
|
||||||
functions. We don't want any specialized templated functions as they won't have
|
functions. We don't want any specialized templated functions as they won't have
|
||||||
|
@ -1064,32 +1084,63 @@ Node *Swig_cparse_template_locate(String *name, Parm *tparms, String *symname, S
|
||||||
templated function with different numbers of template parameters. */
|
templated function with different numbers of template parameters. */
|
||||||
|
|
||||||
if (template_debug) {
|
if (template_debug) {
|
||||||
Printf(stdout, " Not a templated class, seeking most appropriate templated function\n");
|
Printf(stdout, " Not a templated class, seeking all appropriate primary templated functions\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
n = Swig_symbol_clookup_local(name, 0);
|
firstn = Swig_symbol_clookup_local(name, 0);
|
||||||
|
n = firstn;
|
||||||
|
/* First look for all overloaded functions (non-variadic) template matches.
|
||||||
|
* Looking for all template parameter matches only (not function parameter matches)
|
||||||
|
* as %template instantiation uses template parameters without any function parameters. */
|
||||||
while (n) {
|
while (n) {
|
||||||
Parm *tparmsfound = Getattr(n, "templateparms");
|
if (Strcmp(nodeType(n), "template") == 0) {
|
||||||
if (ParmList_len(tparms) == ParmList_len(tparmsfound)) {
|
Parm *tparmsfound = Getattr(n, "templateparms");
|
||||||
/* successful match */
|
if (!ParmList_variadic_parm(tparmsfound)) {
|
||||||
break;
|
if (ParmList_len(instantiated_parms) == ParmList_len(tparmsfound)) {
|
||||||
|
/* successful match */
|
||||||
|
if (template_debug) {
|
||||||
|
Printf(stdout, " found: template <%s> '%s' (%s)\n", ParmList_str_defaultargs(Getattr(n, "templateparms")), name, ParmList_str_defaultargs(Getattr(n, "parms")));
|
||||||
|
}
|
||||||
|
SetFlag(n, "instantiate");
|
||||||
|
if (!match)
|
||||||
|
match = n; /* first match */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* repeat until we find a match with correct number of templated parameters */
|
/* repeat to find all matches with correct number of templated parameters */
|
||||||
n = Getattr(n, "sym:nextSibling");
|
n = Getattr(n, "sym:nextSibling");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!n) {
|
/* Only consider variadic templates if there are no non-variadic template matches */
|
||||||
Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
|
if (!match) {
|
||||||
|
n = firstn;
|
||||||
|
while (n) {
|
||||||
|
if (Strcmp(nodeType(n), "template") == 0) {
|
||||||
|
Parm *tparmsfound = Getattr(n, "templateparms");
|
||||||
|
if (ParmList_variadic_parm(tparmsfound)) {
|
||||||
|
if (ParmList_len(instantiated_parms) >= ParmList_len(tparmsfound) - 1) {
|
||||||
|
/* successful variadic match */
|
||||||
|
if (template_debug) {
|
||||||
|
Printf(stdout, " found: template <%s> '%s' (%s)\n", ParmList_str_defaultargs(Getattr(n, "templateparms")), name, ParmList_str_defaultargs(Getattr(n, "parms")));
|
||||||
|
}
|
||||||
|
SetFlag(n, "instantiate");
|
||||||
|
if (!match)
|
||||||
|
match = n; /* first match */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* repeat to find all matches with correct number of templated parameters */
|
||||||
|
n = Getattr(n, "sym:nextSibling");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((template_debug) && (n)) {
|
if (!match) {
|
||||||
Printf(stdout, "Templated function found: %p\n", n);
|
Swig_error(cparse_file, cparse_line, "Template '%s' undefined.\n", name);
|
||||||
Swig_print_node(n);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
|
@ -1164,24 +1215,24 @@ static void expand_defaults(ParmList *expanded_templateparms) {
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* Swig_cparse_template_parms_expand()
|
* Swig_cparse_template_parms_expand()
|
||||||
*
|
*
|
||||||
* instantiated_parameters: template parameters passed to %template
|
* instantiated_parms: template parameters passed to %template
|
||||||
* primary: primary template node
|
* primary: primary template node
|
||||||
*
|
*
|
||||||
* Expand the instantiated_parameters and return a parameter list with default
|
* Expand the instantiated_parms and return a parameter list with default
|
||||||
* arguments filled in where necessary.
|
* arguments filled in where necessary.
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, Node *primary) {
|
ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parms, Node *primary) {
|
||||||
ParmList *expanded_templateparms = 0;
|
ParmList *expanded_templateparms = 0;
|
||||||
ParmList *templateparms = Getattr(primary, "templateparms");
|
ParmList *templateparms = Getattr(primary, "templateparms");
|
||||||
|
|
||||||
if (Equal(Getattr(primary, "templatetype"), "class")) {
|
if (Equal(Getattr(primary, "templatetype"), "class")) {
|
||||||
/* Templated class */
|
/* Templated class */
|
||||||
expanded_templateparms = CopyParmList(instantiated_parameters);
|
expanded_templateparms = CopyParmList(instantiated_parms);
|
||||||
int variadic = merge_parameters(expanded_templateparms, templateparms);
|
int variadic = merge_parameters(expanded_templateparms, templateparms);
|
||||||
/* Add default arguments from primary template */
|
/* Add default arguments from primary template */
|
||||||
if (!variadic) {
|
if (!variadic) {
|
||||||
ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parameters));
|
ParmList *defaults_start = ParmList_nth_parm(templateparms, ParmList_len(instantiated_parms));
|
||||||
if (defaults_start) {
|
if (defaults_start) {
|
||||||
ParmList *defaults = CopyParmList(defaults_start);
|
ParmList *defaults = CopyParmList(defaults_start);
|
||||||
mark_defaults(defaults);
|
mark_defaults(defaults);
|
||||||
|
@ -1192,7 +1243,7 @@ ParmList *Swig_cparse_template_parms_expand(ParmList *instantiated_parameters, N
|
||||||
} else {
|
} else {
|
||||||
/* Templated function */
|
/* Templated function */
|
||||||
/* TODO: Default template parameters support was only added in C++11 */
|
/* TODO: Default template parameters support was only added in C++11 */
|
||||||
expanded_templateparms = CopyParmList(instantiated_parameters);
|
expanded_templateparms = CopyParmList(instantiated_parms);
|
||||||
merge_parameters(expanded_templateparms, templateparms);
|
merge_parameters(expanded_templateparms, templateparms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue