Using SWIG 3.0.0, I am trying to get SWIG to handle (or at least not crash) when I try to define a template of a class that inherits from a specialized template instance of itself. Here is a toy program to illustrate the issue:
template <typename T, int N = 0> class A; template <typename T> class A<T, 0> { public: A() : mFoo(NULL) {} virtual ~A() {} T* getFoo() { return mFoo; } protected: T* mFoo; }; template <typename T, int N = 0> class A : public A<T, 0> { public: A() : A<T, 0>(), mBar(N) {} virtual ~A() {} int getBar() const { return mBar; } protected: int mBar; };
then in the .i file, I try
%template(tA) A<char, 0>; // causes SWIG to crash
or
%template(tABase) A<char, 0>; // causes SWIG to crash %template(tA) A<char>;
or
%template() A<char, 0>; // doesn't crash (yay!) %template(tA) A<char>; // tA ends up with only the methods of T<A, N> and does NOT inherit from T<A, 0> (poop!)
A more thorough description of the problem is also at http://stackoverflow.com/questions/23000390/handling-class-inheritance-from-specialized-instance-of-self-in-swig
A C++ compiler doesn't like your code, g++ gives:
example_wrap.cxx:216:40: error: redefinition of default argument for ‘int N’
template <typename T,="" int="" N="0"> class A : public A<T, 0="">
^
example_wrap.cxx:214:31: note: original definition appeared here
template <typename T,="" int="" N="0"> class A;
^
If you change:
to
and put the specialization after the full template declaration then
will work. There are of course still problems with SWIG, but you at least have a workaround.
The original invalid input still causes a crash with SWIG git master, but there is now a warning:
Just removing the
= 0
as suggested above gives an example with GCC and clang seem to think is valid, but SWIG still crashes (which seems worse than a crash on invalid C++):Current git master (2e1506c1896f90456e5b3092ba7c7200c1b1e2e1) now emits two errors, but then still segfaults (with both the original and with
= 0
removed to make it valid C++):The crash is due to an infinite recursion, which this patch fixes:
This change just results in a segfault later on (I can tell it's later because the crash above is before SWIG complains if no module name is specified but the new crash is after that).
The new crash is fixed by this:
With both patches SWIG completes without crashing!
However these patches seem like they are papering over the problem - it'll still be there for other code to fall into. It seems to me we generally should not be creating structures which contain themselves like this (certainly in the first case as a class can't be a base class of itself - I'm less clear what the second structure actually is). I don't think I understand this area of SWIG enough to easily find where these get built though. @wsfulton Ideas?