As the title question suggests, I am trying to use SWIG to wrap a function defined in C++ which has as one of its variables a reference to a vector of structures used as both input and output (common in C++) so that the function can be used in Python.
I am using SWIG version 4.0.0 and Python 3.6 64-bit with Visual Studio 2015 (v140 compiler).
The issue highlighted above is common practice in C++, so it was surprising to not be able to find an example that describes how to achieve it using SWIG to wrap the function defined in C++ to be used in python. The following links are the closest thing I could find as examples:
Use struct in SWIG argout typemap
How to pass list of structs to C in SWIG/Python
but they didn't help resolve the issue described below:
The first thing I tried was to use typemaps with the INOUT option in the SWIG interface file which is given by:
/* File : ParserLib.i */
%module ParserLib
%include "typemaps.i"
%include "std_vector.i"
%{
#include "Structures.h"
#include "Read.h"
%}
%apply int *INOUT { int &nNumber };
%apply std::vector<stData> *INOUT { std::vector<stData> &data };
%include "Structures.h"
%include "Read.h"
%template(Struct) std::vector<stData>;
where stData is a structure defined in Structures.h while the function declaration that references both nNumber and data are in Read.h.
However, when I attempt to compile the interface file I get the warning message:
warning 453: Can't apply (std::vector< stData > *INOUT). No typemaps are defined.
So I did some further searching and found the blog:
How do I use SWIG typemaps to marshall structure members from C++ to C# using P/Invoke?
which basically says in a response:
"... Is it possible for you to use a vector of structs instead? I've had no problems passing vectors of structs or custom objects by simply including std_vector.i and relevant typemaps, eg:
%include "std_vector.i
%typemap(MyClassVec) std::vector<MyClass>;
"
So I tried to add:
%typemap(vecOfStruct) std::vector<stData>;
to the interface file (provided above) in the position above the calls to apply, but still get the same warning message when compiling the interface file.
Now I know that this is just a warning message and the interface file does still compile, but I don't get the usual behaviour one would expect in Python when using apply with INOUT, i.e., input a variable into the function and get the output returned by the function.
I should also point out that the template definition:
%template(vecOfStruct) std::vector<stData>;
allows me to define a vector of structs in Python and pass into the function call - which is necessary otherwise I get typedef mismatch errors - that actually runs, but I get some unusual behaviour when working in Python.
Below is a sample of the Python script I used to run the c++ library wrapped by SWIG:
from ParserLib import vecOfStruct, Read
vecOfStruct = vecOfStruct()
Read = Read()
file = "file path and name to be read in"
tempNum = Read.ReadData(file, vecOfStruct, 0)
print(int(tempNum[1]))
v0 = vecOfStruct[0].data1
print(v0)
tempNum = Read.ReadData(file, vecOfStruct, tempNum[1])
Now here the function call is populating tempNum as a list (or array) with values:
[<Swig Object of type 'BOOL *' at 0x0000000005248300>, 100],
hence why the second element in the list is being called in order to print the result; I am not sure what the first element is referring to though. Interestingly, I am still able to access information from vecOfStruct (a class in python) without it actually being set as a return value to the function call. But when I attempt to recall the read function and pass vecOfStruct in as an input, it does not append to the (now populated) vecOfStruct from the first function call.
The intention is to call the function as:
Struct, tempNum = Read.ReadData(1, Struct, 0)
in a loop and be able to pass the vecOfStruct back in having it append the data from different files.