swig/Examples/test-suite/template_partial_specialization_more.i
William S Fulton 817c700ced Template partial specialization improvements
Closes #1300

Changes to support the first example below (partial specialization of
template parameter types like Vect<int>). Previous implementation and
design could only handle one template parameter name per template
specialization argument, such as Vect<TS> for the first template
specialization argument (for first example below)
  template<class TS, typename TTS> class Foo<Vect<TS>, int> { ... };
and not
  template<class TS, typename TTS> class Foo<Vect<TS, TTS>, int> { ... };
New approach is to not modify 'templateparms' in the template node,
(except to fill in default args from primary template)
Previous implementation also assumed a template parameter could not be
used more than once in the specialized arguments, such as
  template<typename T> struct Hey<T, T> { void specialA() {} };

Examples
========
1) For primary:
  template<class T, typename TT> class Foo { ... };
and specialization:
  template<class TS, typename TTS> class Foo<Vect<TS>, TTS> { ... };

Fix specialization template from (wrong)
| templateparms - 'Vect< TS >,typename TTS'
to (correct/new way)
| templateparms - 'class TS,typename TTS'

2) For primary:
  template<typename P1 = int, typename P2 = double> struct Partialler { void primary(P1, P2) {}; };
and specialization:
  template<typename S1, typename S2> struct Partialler<S2, S1*> { void special(S1*, S2, bool) {}; };

Specialized template changes from (wrong)
| templateparms - 'typename S2=int,typename S1=double'
to (correct/new way, default args are removed)
| templateparms - 'typename S1,typename S2'

and subsequent change to partialargs from
| partialargs  - "Partialler<($1,p.$2)>"
to
| partialargs  - "Partialler<($2,p.$1)>"
so that the $n number is now more logically the nth template parameter in templateparms

3) For primary:
  template<typename X, typename Y> struct Hey { void primary() {} };
and specialization:
  template<typename T> struct Hey<T, T> { void specialA() {} };

old (wrong/old way)
| templateparms - 'typename T,typename T'
new (correct/new way)
| templateparms - 'typename T'

These are unchanged and are okay:
| partialargs  - "Hey<($1,$1)>"

4) For primary:
  enum Hello { hi, hello };
  template <Hello, class A> struct C {};
and specialization:
  template <class A> struct C<hello,A> { ... };

old (wrong/old way)
| templateparms - 'hello,class A'
new (correct/new way)
| templateparms - 'class A'

and subsequent changes to partialargs from
| partialargs  - "C<(hi,$2)>"
to
| partialargs  - "C<(hi,$1)>"

Test-suite
==========
Identical output as before in Python but in Java, an unimportant change
in cpp11_variadic_function_templates.i results in one variadic parameter
name being different.

New testcase template_partial_specialization_more.i with more testcases
added including above examples that are not already in the test-suite.
2023-02-17 08:24:25 +00:00

103 lines
3.4 KiB
OpenEdge ABL

%module template_partial_specialization_more
// (1) Based on https://stackoverflow.com/questions/9757642/wrapping-specialised-c-template-class-with-swig
%inline %{
template<typename V> struct Vect {};
template<class T, typename TT>
class Foo {
public:
Foo() {}
virtual ~Foo() {}
T primary() const { return T(); }
};
template<class TS, typename TTS>
class Foo<Vect<TS>, TTS> {
public:
Foo() {}
virtual ~Foo() {}
TS partially_specialized(TS parmin) const { return parmin; }
};
template<>
class Foo<Vect<double>, double> {
public:
Foo() {}
virtual ~Foo() {}
double value_fully_specialized(double d) const { return d; }
};
template<class T, typename TT>
class Foo<T*, TT> {
public:
Foo() {}
virtual ~Foo() {}
int pointer_specialize(T myT) const { return 0; }
};
%}
%template(VectInt) Vect<int>;
%template(FooVectIntDouble) Foo<Vect<int>, double>; // was failing
%template(FooShortPtrDouble) Foo<short*, double>;
%template(FooVectVectInt) Foo<Vect<Vect<int>>, int>; // was failing
// (2) Same types in both args
%inline %{
template<typename X, typename Y> struct Hey { void primary() {} };
template<typename T> struct Hey<T, T> { void special_hey() {} };
%}
%template(HeyInts) Hey<int, int>; // was failing, was calling primary
// (3) Partial specialization using one template parameter instead of two
%inline %{
struct PlainStruct {};
template <typename T, typename U> struct XX { void primary() {} };
template <typename T> struct XX<T, T &> { void special1() {} }; // r.$1
template <typename T> struct XX<T, T const&> { void special2() {} }; // r.q(const).$1
template <typename T> struct XX<T, T *const&> { void special3() {} }; // r.q(const).p.$1
%}
%template(XX1) XX<int, int&>; // was failing, was calling primary
%template(XX2) XX<int, int const&>;
%template(XX3) XX<PlainStruct, PlainStruct *const&>;
// (4) Switching parameters around
%inline %{
#include <iostream>
template<typename P1 = int, typename P2 = double> struct Partialler { void primary(P1, P2) {}; };
template<typename S1, typename S2> struct Partialler<S2, S1*> { void special(S1*, S2, bool) {}; };
%}
%template(PartiallerPrimary) Partialler<short, short>;
%template(PartiallerSpecial) Partialler<int, PlainStruct*>;
// (5) Default args used in specialization, like std::list
%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) {} };
void test_list() {
int myint = 0;
Lyst<int> lis;
lis.primary(myint, Allocator<int>());
PlainStruct ps;
Lyst<PlainStruct *> liss;
liss.specialized1(ps, Allocator<PlainStruct *>());
double mydouble = 0;
Lyst<double **> lissd;
lissd.specialized2(mydouble, (double **)nullptr);
// Lyst<const int&> lissconstint;
// lissconstint.specialized3(myint);
}
%}
%template(LystDouble) Lyst<double>;
//%template(LystDouble) Lyst<short, Allocator<short>>;
%template(LystPlainStructPtr) Lyst<PlainStruct *>;
%template(LystDoublePtrPtr) Lyst<double **>; // called specialized1 instead of specialized2