1

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.

mlachut
  • 11
  • 1
  • Can you show the function declaration for `ReadData` please? This is definitely possible but it's also a whole lot simpler if the function you're using to read the data gives you back a vector that you can then just pass into the other function as is. – Flexo Nov 05 '19 at 08:29
  • Thanks @flexo for the comment/question. The declaration to the function in ReadData is as follows: BOOL Read(std::string file, std::vector &data, int &nNumber); – mlachut Nov 06 '19 at 00:45
  • In regards to your comment @flexo about having a vector as a return to the function, the issue is that there are two referenced input/output variables. From a practical stand point the C++ library could be changed such that both output variables are consolidated somehow and the function returns the result - which will going to be plan B if no resolution is found. – mlachut Nov 06 '19 at 01:04
  • Academically though, if it is possible to use SWIG to have it return two outputs as described in the aforementioned intention, it maybe helpful to others with a similar issue which don't have the luxury of changing the C++ library so that functions return the output instead of it being passed by reference in the function call. – mlachut Nov 06 '19 at 01:08
  • Sure, I'll try and find some time to write up an answer that encompasses both options then. – Flexo Nov 06 '19 at 19:53

0 Answers0