FifthArrow
FifthArrow

Reputation: 185

SWIG Callback with Output Parameters

My goal is to be able to define a function in python which modifies one of its arguments, and then pass this as a callback function to a C++ driver. I've been trying to accomplish this with SWIG and its director classes. Consider the following minimal example:

CPP.h :

class MyOp {
public:
  virtual void SetVal(int& val) {val += 1;};
  virtual ~MyOp() {}
};
int Runner(MyOp *op);

CPP.cc:

#include "CPP.h"
int Runner(MyOp* op) {
  int val = 1;
  op->SetVal(val);
  return val;
}

CPP.i:

%module(directors="1") CPP
%{
#include "CPP.h"
%}
%feature("director") MyOp;
%include "CPP.h"

run.py:

import CPP
class PyOp(CPP.MyOp):
    def SetVal(self, val):
        val += 2
print(CPP.Runner(PyOp()))

Unfortunately, this code segfaults. The director documentation makes a reference to using swig typesmaps, in particular directorin, directorout, and directorargout, unfortunately there are no examples.

I tried a few things with no luck. For example:

%apply int &DIRECTORARGOUT { int &val };

But this gives me a warning at compile time:

CPP.i:7: Warning 453: Can't apply (int &DIRECTORARGOUT). No typemaps are defined.

and crashes at run time. Interestingly enough, using DIRECTOROUT has no compile time warning, but also crashes. If you print out the value of val inside the python function:

class PyOp(CPP.MyOp):
    def SetVal(self, val):
        print(val)
        val += 2

You can see that the type of val is <Swig Object of type 'int *' at 0x1053f5de0>. So I thought about using cpointer.i to fix it. But even trying to dereference val with intp_value causes a crash.

I suppose I could try to avoid this whole issue by just having the output values I want (often times more than 1) be a member of the class MyOp, but it seems like there should be a good way to do this, and I'd appreciate any help finding it.

Upvotes: 0

Views: 759

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177901

The cpointer.i solution worked for me. You'd have to show a minimal, complete, verifiable example to fix your crash. I just changed the following files:

CPP.i:

%module(directors="1") CPP
%{
#include "CPP.h"
%}
%feature("director") MyOp;
%include "cpointer.i"
%pointer_functions(int, intp);
%include "CPP.h"

run.py:

import CPP
class PyOp(CPP.MyOp):
    def SetVal(self, val):
        i = CPP.intp_value(val)
        i += 2
        CPP.intp_assign(val,i)
print(CPP.Runner(PyOp()))

Output:

C:\>run
3

Upvotes: 1

Related Questions