I need to wrap a C++ library with SWIG to use it with Java.
I have already some methods working but I have encountered a situation that I don’t know how to solve it.
I have a couple of methods like this:
void method1(std::string & name, std::string & result);
bool method2(std::string & name, std::string & alias, std::string & resurnValue, std::string & returnType);
Note: Actually this are member methods of a class named MyClass.
I could change the first method to return a std::string instead of being void, and that should work; but I have no idea how to handle the second method where the two last parameters are output parameters. I have seen a couple of questions refereeing to char * output params (Passing multiple parameters and allocating strings in C using Swig/Python), but in my case should be a std::string and the Documentation of SWIG doesn’t mention this situation enter link description here. Also I probably encounter more methods returning 3 or more output params, probably with different types.
Finally I have a little of control about the interface, I’m also developing a class that acts as an entry point to the library, but it just passes call to the real implementation.
For example by this I have managed to change a method like method3(std::string & s) to method3(const std::string & s), so I could use it from Java with a normal String.
So modifying a little bit the methods signatures is possible, but if a native method returns n outputs parameters I should return all of them (I can’t create new methods to return each one).
Update:
I have been looking at the solution given by Flexo and works great, however i’m considering doing a class to wrap std::string and using that to interact with returned strings, is a very similar approach to the second solution of Flexo, but using this StringWrapper instead of using a java String array, basically looks like this:
/*
* The MyClass.i file
*/
%module example
%include "std_string.i"
%{
class StringPtr{
private:
stdString str;
public:
StringPtr(){
}
StringPtr(const stdString & str){
this->str = stdString(str);
}
stdString & getStrRef(){
return (this->str);
}
stdString getStrVal(){
return stdString(this->str);
}
~StringPtr(){
}
};
%}
/////////////////// Export StringPtr to Java
class StringPtr{
public:
StringPtr();
StringPtr(const stdString & str);
stdString getStrVal();
~StringPtr();
};
// I think this is nor necessary
%rename ("$ignore", fullname=1) "StringPtr::getStrRef";
%extend MyClass {
void method1(cons std::string & name, StringPtr & result){
$self->method1(name, result.getStrRef());
}
bool method2(cons std::string & name, cons std::string & alias, StringPtr & returnValue, StringPtr & returnType){
$self->method2(name, alias, returnValue.getStrRef(), returnType.getStrRef());
}
};
%rename ("$ignore", fullname=1) "MyClass::method1";
%rename ("$ignore", fullname=1) "MyClass::method2";
%include "MyClass.h"
So i’m wondering, from a performance point of view, witch is better, the structs solution (by Flexo), the string array by Flexo or this pointer (just like a struct with only one member.
Assuming you want to wrap this without modifying the existing header file there are two ways that come to mind. Given the header file I used for testing:
The simplest way to wrap it is to use
%inlineto create an overload that wraps all the outputs in one type:This works with:
You could have used
std::pairorboost::tuplewith%templatebut wrappingboost::tupleis non-trivial I suspect and like this you get to name the members something appropriate that users of your library will understand rather than justfirstandsecond, without using%renamewhich becomes more verbose than just writing a custom struct within%inline.Alternatively SWIG provides OUTPUT typemaps that you can use with
%applyto create output argumnets. These get wrapped as an array of 1 element – the semantics of passing arrays matches that of output arguments. Unfortunately there isn’t one forstd::stringin typemaps.i, so we have to write our own. Ideally I’d have reused theOUTPUT_TYPEMAPmacro from that file and just modified the argout typemap slightly, but it gets#undefined without that being possible. Fortunately it’s fairly simple to just duplicate and modify for this case:This can be used like:
Both of these were tested and worked on my system. For this instance I like the
%inlineapproach. (If it were a member function you’d use%extendinstead). In the general case the OUTPUT typemaps can be applied without writing any extra code though.