From: William S F. <ws...@fu...> - 2017-07-01 11:04:14
|
On 25 June 2017 at 19:32, Georgios Petasis via Swig-user < swi...@li...> wrote: > Hi all, > > I have two C++ classes (SpanSet & Annotation), which I expose as C++ > classes in Tcl through swig, but also through an API that is closer to C > (although still I am using overloading). In this API, I cast pointer to > class objects in C structs (CDM_SpanSet, CDM_Annotation). > > I have a function that can take pointers from both: > > A: AddSpan(CDM_SpanSet, const CDM_Span); > > B: AddSpan(CDM_SpanSet, int start, int end) > > C: AddSpan(CDM_Annotation, const CDM_Span); > > D: AddSpan(CDM_Annotation, int start, int end); > > The code that swig generates is similar to: > > If there are two args, if 1st arg is SWIGTYPE_p_CDM_SpanSet_t, call A, > else C. > > If there are 3 args, if 1st arg is SWIGTYPE_p_CDM_SpanSet_t call B, else D. > > What is the problem: I have defined in/out templates, which actually > interface better these values with Tcl objects. > > With my templates, a string representation of the pointer is never > returned: the pointers are placed in Tcl objects that hold this pointer. > And my code can even derive a pointer from a Tcl representation. > > So, to a non-overloaded AddSpan(CDM_SpanSet, ...), CDM_SpanSet can be any > of: > > 1: A pointer, like _20dc240200000000_p_ELEP__CDM__SpanSet (i.e. created > from CDM::SpanSet, the "class" interface swig provides). > > 2: A Tcl object, like "{}" (actually a nested Tcl list). If it is an > object that holds a SpanSet object, it is converted. > > 3: A tcl object of type SpanSet, returned from another API call (like > CreateSpanSet). > > The problem is that the code that swig generates, can handle only case 1. > My input templates are ignored when the function that will handle > overloading is generated. > > Looking at the documentation, it seems I have to also define a typecheck > template. > > But Tcl generator does not use the typecheck templates The typecheck typemaps are used. To demonstrate, I use this: %module example %inline %{ struct CDM_SpanSet {}; struct CDM_Annotation {}; const char * AddSpan(CDM_SpanSet spanset, int start, int end) { return "AddSpan(CDM_SpanSet...)"; } const char * AddSpan(CDM_Annotation annotation, int start, int end) { return "AddSpan(CDM_Annotation...)"; } %} and run with the option to show the typemaps used and grep to filter out for the annotation parameter: $ swig -tcl8 -c++ -debug-tmused -o example_wrap.cxx example.i | grep annotation example.i:6: Typemap for CDM_SpanSet spanset (in) : %typemap(in) SWIGTYPE example.i:6: Typemap for CDM_SpanSet spanset (typecheck) : %typemap(typecheck) SWIGTYPE It is quite clear the typecheck typemap is used, and if you look in the generated c++ code you should find code that does the type checking (see the _wrap_AddSpan function). Take the default SWIGTYPE typemap (which you can find if you run swig -E and look for it). If you add it into your interface file before the use of CDM_Spanet and change it to target the CDM_SpanSet type, then you can modify and enhance it as you like: %typemap(typecheck,precedence= 0 ,noblock=1) CDM_SpanSet { void *vptr = 0; int res = SWIG_ConvertPtr($input, &vptr, $&descriptor, 0); $1 = SWIG_CheckState(res); // add in your custom modifications to try convert $input to "{}" if the above fails } If you run with -debug-tmused again, it will use the more specific typemap above. Please have a good look at http://swig.org/Doc3.0/Typemaps.html. William |