Improved template template parameters support.
Previously, specifying more than one simple template template parameter
resulted in a parse error. Now multiple template template parameters are
working including instantiation with %template. Example:
template <template<template<class> class, class> class Op, template<class> class X, class Y>
class C { ... };
Closes #624
Closes #1021
This commit is contained in:
parent
c85e7f1625
commit
05b93b1f06
9 changed files with 212 additions and 62 deletions
|
|
@ -7,6 +7,15 @@ 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)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2022-12-02: wsfulton
|
||||||
|
#624 #1021 Improved template template parameters support. Previously, specifying more
|
||||||
|
than one simple template template parameter resulted in a parse error. Now
|
||||||
|
multiple template template parameters are working including instantiation with
|
||||||
|
%template. Example:
|
||||||
|
|
||||||
|
template <template<template<class> class, class> class Op, template<class> class X, class Y>
|
||||||
|
class C { ... };
|
||||||
|
|
||||||
2022-11-29: bero
|
2022-11-29: bero
|
||||||
Fix mismatch between #pragma GCC diagnostic push and pop statements
|
Fix mismatch between #pragma GCC diagnostic push and pop statements
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -497,6 +497,7 @@ CPP_TEST_CASES += \
|
||||||
template_static \
|
template_static \
|
||||||
template_tbase_template \
|
template_tbase_template \
|
||||||
template_template_parameters \
|
template_template_parameters \
|
||||||
|
template_template_template_parameters \
|
||||||
template_typedef \
|
template_typedef \
|
||||||
template_typedef_class_template \
|
template_typedef_class_template \
|
||||||
template_typedef_cplx \
|
template_typedef_cplx \
|
||||||
|
|
|
||||||
|
|
@ -112,3 +112,39 @@ using callback_t = int(*)(int);
|
||||||
callback_t get_callback() { return mult2; }
|
callback_t get_callback() { return mult2; }
|
||||||
int call(callback_t funk, int param) { return funk(param); }
|
int call(callback_t funk, int param) { return funk(param); }
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
||||||
|
// Template template parameters - from #1021
|
||||||
|
%inline %{
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
class Node {};
|
||||||
|
struct AnyVal { typedef AnyVal Super; };
|
||||||
|
|
||||||
|
template<template<typename D, typename O> class C, typename T, typename Super, typename Root, typename O>
|
||||||
|
using DeriveToBase = typename std::conditional<std::is_same<T, AnyVal>::value, Root, C<Super, O> >::type;
|
||||||
|
|
||||||
|
template<class T, class Root, class RParent>
|
||||||
|
using ImmediateBase = typename std::conditional<std::is_same<T, AnyVal>::value, Root, RParent >::type;
|
||||||
|
|
||||||
|
template<class D, typename _Super=AnyVal> class Expression {
|
||||||
|
typedef _Super Super;
|
||||||
|
};
|
||||||
|
|
||||||
|
void TestInstantiationsPart4() {
|
||||||
|
Expression<AnyVal, AnyVal::Super> express;
|
||||||
|
DeriveToBase<Expression, AnyVal, AnyVal, AnyVal, AnyVal> derive_to_base = AnyVal();
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO define and instantiate std::conditional and std::is_same
|
||||||
|
%template(ExpressionInstantiation) Expression<AnyVal, AnyVal::Super>;
|
||||||
|
%template(AnyTypeInstantiation) DeriveToBase<Expression, AnyVal, AnyVal, AnyVal, AnyVal>;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
AnyVal takeAnyVal(DeriveToBase<Expression, AnyVal, AnyVal, AnyVal, AnyVal> av) {
|
||||||
|
return av;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ public class template_template_parameters_runme {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
// Test first part
|
// Test part 1
|
||||||
ListFastBool listBool = new ListFastBool();
|
ListFastBool listBool = new ListFastBool();
|
||||||
listBool.setItem(true);
|
listBool.setItem(true);
|
||||||
boolean x_boolean = listBool.getAllotype();
|
boolean x_boolean = listBool.getAllotype();
|
||||||
|
|
@ -27,7 +27,7 @@ public class template_template_parameters_runme {
|
||||||
if (listDouble.getItem() != 10.2)
|
if (listDouble.getItem() != 10.2)
|
||||||
throw new RuntimeException("Failed");
|
throw new RuntimeException("Failed");
|
||||||
|
|
||||||
// Test second part
|
// Test part 2
|
||||||
FloatTestStruct floatTestStruct = new FloatTestStruct();
|
FloatTestStruct floatTestStruct = new FloatTestStruct();
|
||||||
FloatContainer2 floatContainer2 = floatTestStruct.getX();
|
FloatContainer2 floatContainer2 = floatTestStruct.getX();
|
||||||
floatContainer2.setX(8.1f);
|
floatContainer2.setX(8.1f);
|
||||||
|
|
@ -41,6 +41,10 @@ public class template_template_parameters_runme {
|
||||||
IntTestStruct intTestStructReturned = template_template_parameters.TestStructContainer1Method(intTestStruct);
|
IntTestStruct intTestStructReturned = template_template_parameters.TestStructContainer1Method(intTestStruct);
|
||||||
if (intTestStructReturned.getX().getX() != 101)
|
if (intTestStructReturned.getX().getX() != 101)
|
||||||
throw new RuntimeException("Failed");
|
throw new RuntimeException("Failed");
|
||||||
|
|
||||||
|
// Test part 3
|
||||||
|
MyFootInt99 mfi99 = new MyFootInt99();
|
||||||
|
mfi99.OperatorPlusEquals(mfi99);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
|
||||||
|
import template_template_template_parameters.*;
|
||||||
|
|
||||||
|
public class template_template_template_parameters_runme {
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
System.loadLibrary("template_template_template_parameters");
|
||||||
|
} 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[]) {
|
||||||
|
CustomAttrs custom_attrs = new CustomAttrs();
|
||||||
|
AC ac = new AC();
|
||||||
|
BAC bac = new BAC();
|
||||||
|
CBAC cbac = new CBAC();
|
||||||
|
DBAC dbac = new DBAC();
|
||||||
|
|
||||||
|
custom_attrs = ac.getAttributes();
|
||||||
|
custom_attrs = bac.getAttributes();
|
||||||
|
custom_attrs = cbac.getAttributes();
|
||||||
|
custom_attrs = dbac.getAttributes();
|
||||||
|
|
||||||
|
bac.BMethod(custom_attrs, ac);
|
||||||
|
cbac.BMethod(custom_attrs, ac);
|
||||||
|
dbac.BMethod(custom_attrs, ac);
|
||||||
|
|
||||||
|
cbac.CMethod(custom_attrs, bac);
|
||||||
|
dbac.DMethod(custom_attrs, bac);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from template_template_parameters import *
|
from template_template_parameters import *
|
||||||
|
|
||||||
# Test first part
|
# Test part 1
|
||||||
listBool = ListFastBool()
|
listBool = ListFastBool()
|
||||||
listBool.item = True
|
listBool.item = True
|
||||||
x_boolean = listBool.allotype
|
x_boolean = listBool.allotype
|
||||||
|
|
@ -13,7 +13,7 @@ x_double = listDouble.allotype
|
||||||
if listDouble.item != 10.2:
|
if listDouble.item != 10.2:
|
||||||
raise RuntimeError("Failed")
|
raise RuntimeError("Failed")
|
||||||
|
|
||||||
# Test second part
|
# Test part 2
|
||||||
floatTestStruct = FloatTestStruct()
|
floatTestStruct = FloatTestStruct()
|
||||||
floatContainer2 = floatTestStruct.x
|
floatContainer2 = floatTestStruct.x
|
||||||
floatContainer2.x = 8.1
|
floatContainer2.x = 8.1
|
||||||
|
|
@ -28,3 +28,6 @@ intTestStructReturned = TestStructContainer1Method(intTestStruct)
|
||||||
if intTestStructReturned.x.x != 101:
|
if intTestStructReturned.x.x != 101:
|
||||||
raise RuntimeError("Failed")
|
raise RuntimeError("Failed")
|
||||||
|
|
||||||
|
# Test part 3
|
||||||
|
mfi99 = MyFootInt99()
|
||||||
|
mfi99 += mfi99 # __iadd__
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
%module template_template_parameters
|
%module template_template_parameters
|
||||||
|
|
||||||
|
|
||||||
%inline %{
|
%inline %{
|
||||||
|
|
||||||
/* part 1 */
|
// part 1
|
||||||
|
|
||||||
namespace pfc {
|
namespace pfc {
|
||||||
template<typename t_item, template <typename> class t_alloc> class array_t {};
|
template<typename t_item, template <typename> class t_alloc> class array_t {};
|
||||||
|
|
@ -33,7 +32,7 @@ void TestInstantiations() {
|
||||||
(void) myListImplInt;
|
(void) myListImplInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* part 2 */
|
// part 2
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct Container1 {
|
struct Container1 {
|
||||||
|
|
@ -52,10 +51,10 @@ TestStruct<int, Container1> TestStructContainer1Method(TestStruct<int, Container
|
||||||
ts1.x.x += 10;
|
ts1.x.x += 10;
|
||||||
return ts1;
|
return ts1;
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
/* part 1 */
|
|
||||||
|
// part 1
|
||||||
%template(ListImplFastBool) list_impl_t<bool, pfc::array_t<bool, pfc::alloc_fast> >;
|
%template(ListImplFastBool) list_impl_t<bool, pfc::array_t<bool, pfc::alloc_fast> >;
|
||||||
%template(ListFastBool) list_tt<bool, pfc::alloc_fast>;
|
%template(ListFastBool) list_tt<bool, pfc::alloc_fast>;
|
||||||
|
|
||||||
|
|
@ -65,9 +64,31 @@ TestStruct<int, Container1> TestStructContainer1Method(TestStruct<int, Container
|
||||||
%template(BoolAllocFast) pfc::alloc_fast<bool>;
|
%template(BoolAllocFast) pfc::alloc_fast<bool>;
|
||||||
%template(DoubleAllocFast) pfc::alloc_fast<double>;
|
%template(DoubleAllocFast) pfc::alloc_fast<double>;
|
||||||
|
|
||||||
/* part 2 */
|
// part 2
|
||||||
%template(IntContainer1) Container1<int>;
|
%template(IntContainer1) Container1<int>;
|
||||||
%template(FloatContainer2) Container2<float>;
|
%template(FloatContainer2) Container2<float>;
|
||||||
%template(IntTestStruct) TestStruct<int, Container1>;
|
%template(IntTestStruct) TestStruct<int, Container1>;
|
||||||
%template(FloatTestStruct) TestStruct<float, Container2>;
|
%template(FloatTestStruct) TestStruct<float, Container2>;
|
||||||
|
|
||||||
|
|
||||||
|
// part 3 - from #624
|
||||||
|
|
||||||
|
%rename("") operator+=; // For Ruby and Octave that ignore operator+=
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
template<typename T, int dim> struct Foot {
|
||||||
|
template <template <typename, int> class X, typename U>
|
||||||
|
void operator+=(X<U, dim> & ref) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void TestInstantiationsPart3() {
|
||||||
|
Foot<int, 99> MyFootInt99;
|
||||||
|
MyFootInt99.operator+=<Foot, int>(MyFootInt99);
|
||||||
|
MyFootInt99 += MyFootInt99;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%template(MyFootInt99) Foot<int, 99>;
|
||||||
|
%extend Foot<int, 99> {
|
||||||
|
%template(OperatorPlusEquals) operator+=<Foot, int>;
|
||||||
|
}
|
||||||
|
|
|
||||||
45
Examples/test-suite/template_template_template_parameters.i
Normal file
45
Examples/test-suite/template_template_template_parameters.i
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
%module template_template_template_parameters
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
// Github issue #624
|
||||||
|
class CustomAttrs {
|
||||||
|
public:
|
||||||
|
enum dattr1d {pos, vel, someCustomCaseVar, d1dLast};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
TT attributes;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template<class> class A, class T>
|
||||||
|
class B : public A<T> {
|
||||||
|
public:
|
||||||
|
virtual void BMethod(T t_parm, A<T> at_parm) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template<template<class> class, class> class Op, template<class> class X, class Y>
|
||||||
|
class C : public Op<X,Y> {
|
||||||
|
public:
|
||||||
|
virtual void CMethod(Y y_parm, Op<X, Y> opxy_parm) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <template<template<class K1> class K2, class K3> class L, template<class K4> class M, class N>
|
||||||
|
class D : public L<M,N> {
|
||||||
|
public:
|
||||||
|
virtual void DMethod(N n_parm, L<M, N> lmn_parm) {}
|
||||||
|
};
|
||||||
|
%}
|
||||||
|
|
||||||
|
%{
|
||||||
|
template class A<CustomAttrs>;
|
||||||
|
template class B<A, CustomAttrs>;
|
||||||
|
template class C<B, A, CustomAttrs>;
|
||||||
|
template class D<B, A, CustomAttrs>;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%template(AC) A<CustomAttrs>;
|
||||||
|
%template(BAC) B<A, CustomAttrs>;
|
||||||
|
%template(CBAC) C<B, A, CustomAttrs>;
|
||||||
|
%template(DBAC) D<B, A, CustomAttrs>;
|
||||||
|
|
@ -1681,7 +1681,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
|
||||||
%type <dtype> initializer cpp_const exception_specification cv_ref_qualifier qualifiers_exception_specification;
|
%type <dtype> initializer cpp_const exception_specification cv_ref_qualifier qualifiers_exception_specification;
|
||||||
%type <id> storage_class extern_string;
|
%type <id> storage_class extern_string;
|
||||||
%type <pl> parms ptail rawparms varargs_parms ;
|
%type <pl> parms ptail rawparms varargs_parms ;
|
||||||
%type <pl> templateparameters templateparameterstail;
|
%type <pl> templateparameterstail;
|
||||||
%type <p> parm_no_dox parm valparm rawvalparms valparms valptail ;
|
%type <p> parm_no_dox parm valparm rawvalparms valparms valptail ;
|
||||||
%type <p> typemap_parm tm_list tm_tail ;
|
%type <p> typemap_parm tm_list tm_tail ;
|
||||||
%type <p> templateparameter ;
|
%type <p> templateparameter ;
|
||||||
|
|
@ -4446,43 +4446,7 @@ cpp_template_possible: c_decl {
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
template_parms : templateparameters {
|
template_parms : templateparameter templateparameterstail {
|
||||||
/* Rip out the parameter names */
|
|
||||||
Parm *p = $1;
|
|
||||||
$$ = $1;
|
|
||||||
|
|
||||||
while (p) {
|
|
||||||
String *name = Getattr(p,"name");
|
|
||||||
if (!name) {
|
|
||||||
/* Hmmm. Maybe it's a 'class T' parameter */
|
|
||||||
char *type = Char(Getattr(p,"type"));
|
|
||||||
/* Template template parameter */
|
|
||||||
if (strncmp(type,"template<class> ",16) == 0) {
|
|
||||||
type += 16;
|
|
||||||
}
|
|
||||||
if ((strncmp(type,"class ",6) == 0) || (strncmp(type,"typename ", 9) == 0)) {
|
|
||||||
char *t = strchr(type,' ');
|
|
||||||
Setattr(p,"name", t+1);
|
|
||||||
} else
|
|
||||||
/* Variadic template args */
|
|
||||||
if ((strncmp(type,"class... ",9) == 0) || (strncmp(type,"typename... ", 12) == 0)) {
|
|
||||||
char *t = strchr(type,' ');
|
|
||||||
Setattr(p,"name", t+1);
|
|
||||||
Setattr(p,"variadic", "1");
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
Swig_error(cparse_file, cparse_line, "Missing template parameter name\n");
|
|
||||||
$$.rparms = 0;
|
|
||||||
$$.parms = 0;
|
|
||||||
break; */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p = nextSibling(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
templateparameters : templateparameter templateparameterstail {
|
|
||||||
set_nextSibling($1,$2);
|
set_nextSibling($1,$2);
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
|
|
@ -4491,10 +4455,52 @@ templateparameters : templateparameter templateparameterstail {
|
||||||
|
|
||||||
templateparameter : templcpptype def_args {
|
templateparameter : templcpptype def_args {
|
||||||
$$ = NewParmWithoutFileLineInfo(NewString($1), 0);
|
$$ = NewParmWithoutFileLineInfo(NewString($1), 0);
|
||||||
|
previousNode = currentNode;
|
||||||
|
currentNode = $$;
|
||||||
|
Setfile($$, cparse_file);
|
||||||
|
Setline($$, cparse_line);
|
||||||
Setattr($$, "value", $2.rawval ? $2.rawval : $2.val);
|
Setattr($$, "value", $2.rawval ? $2.rawval : $2.val);
|
||||||
}
|
}
|
||||||
| parm {
|
| TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype idcolon def_args {
|
||||||
$$ = $1;
|
$$ = NewParmWithoutFileLineInfo(NewStringf("template< %s > %s %s", ParmList_str_defaultargs($3), $5, $6), $6);
|
||||||
|
previousNode = currentNode;
|
||||||
|
currentNode = $$;
|
||||||
|
Setfile($$, cparse_file);
|
||||||
|
Setline($$, cparse_line);
|
||||||
|
if ($7.val) {
|
||||||
|
Setattr($$, "value", $7.val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| TEMPLATE LESSTHAN template_parms GREATERTHAN cpptype def_args {
|
||||||
|
$$ = NewParmWithoutFileLineInfo(NewStringf("template< %s > %s", ParmList_str_defaultargs($3), $5), 0);
|
||||||
|
previousNode = currentNode;
|
||||||
|
currentNode = $$;
|
||||||
|
Setfile($$, cparse_file);
|
||||||
|
Setline($$, cparse_line);
|
||||||
|
if ($6.val) {
|
||||||
|
Setattr($$, "value", $6.val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
| parm {
|
||||||
|
Parm *p = $1;
|
||||||
|
$$ = $1;
|
||||||
|
|
||||||
|
/* TODO: also slice off the name from the "type" */
|
||||||
|
/* Rip out the parameter names */
|
||||||
|
String *name = Getattr(p, "name");
|
||||||
|
if (!name) {
|
||||||
|
String *type = Getattr(p, "type");
|
||||||
|
if ((Strncmp(type, "class ", 6) == 0) || (Strncmp(type, "typename ", 9) == 0)) {
|
||||||
|
/* A 'class T' parameter */
|
||||||
|
const char *t = Strchr(type, ' ');
|
||||||
|
Setattr(p, "name", t + 1);
|
||||||
|
} else if ((Strncmp(type, "class... ", 9) == 0) || (Strncmp(type, "typename... ", 12) == 0)) {
|
||||||
|
/* Variadic template args */
|
||||||
|
const char *t = Strchr(type, ' ');
|
||||||
|
Setattr(p, "name", t + 1);
|
||||||
|
Setattr(p, "variadic", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -5195,17 +5201,6 @@ parm_no_dox : rawtype parameter_declarator {
|
||||||
Setattr($$,"value",$2.defarg);
|
Setattr($$,"value",$2.defarg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
| TEMPLATE LESSTHAN cpptype GREATERTHAN cpptype idcolon def_args {
|
|
||||||
$$ = NewParmWithoutFileLineInfo(NewStringf("template<class> %s %s", $5,$6), 0);
|
|
||||||
previousNode = currentNode;
|
|
||||||
currentNode = $$;
|
|
||||||
Setfile($$,cparse_file);
|
|
||||||
Setline($$,cparse_line);
|
|
||||||
if ($7.val) {
|
|
||||||
Setattr($$,"value",$7.val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
| ELLIPSIS {
|
| ELLIPSIS {
|
||||||
SwigType *t = NewString("v(...)");
|
SwigType *t = NewString("v(...)");
|
||||||
$$ = NewParmWithoutFileLineInfo(t, 0);
|
$$ = NewParmWithoutFileLineInfo(t, 0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue