To work with these examples, I created the following header file:
template<typename T> struct MyTemplateClass { bool Validate(T* _in) { return false; }
The good news is that you can actually generate the code you request is much simpler than what you tried. We can just use the csout map map, which is valid only for Validate , and we are good to go:
%module test %{ #include "test.hh" %} %typemap(csout, excode=SWIGEXCODE) bool Validate {
For completeness, although let us look at the original question as posed. First, simplify things by making MyTemplateClass actually not a template (i.e. Comment out line 1 of test.hh and add a typedef for T somewhere instead).
In this case, what you were trying to do pretty much works using $typemap(cstype, T) to search for the C # type used for that type during SWIG compilation:
%module test %{ #include "test.hh" %} %typemap(cscode) MyTemplateClass %{ public bool Validate($typemap(cstype, T) in) { return in.swigCMemOwn && InternalValidate(in); } %} %rename(InternalValidate) Validate; %include "test.hh"
However, when we return to the template again, the generated code is incorrect, created by Validate :
public bool Validate(SWIGTYPE_p_T in)
This is because SWIG (at least 3.0, from Ubuntu 14.04) does not know anything about T in this context - the template is replaced incorrectly. I'm not quite sure if this is a mistake or an expected behavior, but in any case this is a problem for us.
Interestingly, however, if you want to write a sample cscode map inside the template definition, which SWIG sees that the replacement works:
%module test %{ #include "test.hh" %} %rename(InternalValidate) Validate; template<typename T> struct MyTemplateClass { bool Validate(T* _in) { return false; } // ... other stuff... MyTemplateClass is also a container for T* %typemap(cscode) MyTemplateClass %{ public bool Validate($typemap(cstype, T) in) { return in.swigCMemOwn && InternalValidate(in); } %} }; struct Foo {}; %template(MyTemplateClassInt) MyTemplateClass<int>; %template(MyTemplateClassFoo) MyTemplateClass<Foo>;
In the above interface, the type for T correctly replaced by the output. Therefore, if you agree to accept duplication between the .i file and the actual header files that you use in the library, then this is enough. You can also edit the header file itself and mix SWIG and C ++ with it, the following modified .hh test will achieve the same result:
template<typename T> struct MyTemplateClass { bool Validate(T* _in) { return false; }
This works because SWIG defines the macro for the SWIG preprocessor, but it will not be defined during normal C ++ compilation, so everything is fine. Personally, I don't like this - I would rather keep the C ++ and SWIG bits logically separated by a clean border.
If you do not want to duplicate this, and cannot / will not simply edit the header file, all is not lost. We can (ab) use %extend so that we do the same:
%module test %{ #include "test.hh" %} %rename(InternalValidate) Validate; %include "test.hh" %extend MyTemplateClass { %typemap(cscode) MyTemplateClass %{ public bool Validate($typemap(cstype, T) in) { return in.swigCMemOwn && InternalValidate(in); } %} } %template(MyTemplateClassInt) MyTemplateClass<int>; %template(MyTemplateClassFoo) MyTemplateClass<Foo>;
What works again.
The final solution is that if you have a typedef inside a template that just uses T, for example:
template<typename T> struct MyTemplateClass { typedef T type;
Then the following works refer to typedef as $1_basetype::type :
%module test %{ #include "test.hh" %} %rename(InternalValidate) Validate; %typemap(cscode) MyTemplateClass %{ public bool Validate($typemap(cstype, $1_basetype::type) in) { return in.swigCMemOwn && InternalValidate(in); } %} %include "test.hh" %template(MyTemplateClassInt) MyTemplateClass<int>; %template(MyTemplateClassFoo) MyTemplateClass<Foo>;
Thus, although there is a simple way that looks as if it should work, it seems that there are still many options that can achieve the desired result.