Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swig shared_ptr macro with templated class and derived classes

Tags:

c++

python

swig

This question is in some ways an extension of the question posted here: SWIG_SHARED_PTR macro with templated class Although perhaps the issue is entirely unrelated.

The basic set up is this: I am trying to get SWIG to wrap a templated class as a shared_ptr. So the interface file should look something like this

%shared_ptr(template_instance)
%include template_class.cpp
%template(vector_instance) template_class<int>;

Now the problem is that template_class has a lot of derived classes, this causes a lot of warnings in swig, and then build errors. These classes do not need to be handled as shared_ptr's, so I would rather just ignore the warnings the above code generates. The solution to the error seems to be:

%shared_ptr(template_derived1)
%shared_ptr(template_derived2)
.
.
.
%shared_ptr(template_derivedn)
%shared_ptr(template_instance)
%include template_class.cpp
%template(vector_instance) template_class<int>;

This works, but is a huge mess, and I assume there must be some disadvantage to having everything represented as a shared_ptr (what is it?). Is there anyone around this?

EDIT: UPDATE WITH SPECIFIC EXAMPLE

test.h

class Base
{
  int base_member;
};

class Derived : public Base
{
  int derived_member;
};

test.i

%module test
%{
#include "test.h"
#include <boost/shared_ptr.hpp>
  %}

%include <boost_shared_ptr.i>
%shared_ptr(Base)
%include test.h

commands:

swig -python -c++ test.i 
g++ -fPIC -I /usr/include/python2.7 -c test_wrap.cxx

In this stripped down example, the swig call gives warnings, and the g++ call gives errors. Note that I've removed the templating, as it didn't seem to be an ingredient in the problem.

The errors are resolved by commenting out

%shared_ptr(Base)

The warning generated by swig is:

test.h:10: Warning 520: Derived class 'Derived' of 'Base' is not similarly marked as a smart pointer

and the error from g++ is:

test_wrap.cxx: In function ‘PyObject* _wrap_delete_Derived(PyObject*, PyObject*)’:
test_wrap.cxx:3155:22: error: ‘smartarg1’ was not declared in this scope
like image 872
GeorgeWilson Avatar asked Jul 08 '12 03:07

GeorgeWilson


1 Answers

The warning here is because you need to tell SWIG about the whole class hierarchy, not just the base class in order to be able to usefully use a smart pointer. It needs to be able to convert between the smart pointers so that anything which takes a smart pointer to Base can also accept one to Derived. So your interface file needs to be:

%module test
%{
#include "test.h"
#include <boost/shared_ptr.hpp>
%}

%include <boost_shared_ptr.i>
%shared_ptr(Base)
%shared_ptr(Derived)
%include "test.h"

which resolved the problem that was warned about and generated code that compiled fine on my machine.

If you don't want to tell SWIG about all the derived types the simplest thing is to hide the type completely from SWIG - only ever expose the Base type from things you want to wrap. You can do that in a few ways, the least intrusive being to change the interface file to:

%module test
%{
#include "test.h"
#include <boost/shared_ptr.hpp>
%}

%include <boost_shared_ptr.i>
%ignore Derived;
%shared_ptr(Base)
%include "test.h"

This causes only Base to be wrapped, so the code that was failing to compile doesn't get generated any more.

Alternatively since that still requires a %ignore per type you can modify the header file to hide the declaration/definition of Derived from SWIG entirely:

class Base
{
  int base_member;
};
#ifndef SWIG
class Derived : public Base
{
  int derived_member;
};
#endif

If your project is organised such that there's one header file per type (roughly) you might be able to do this in a much simpler way by simply not using %include with the files other than the base one.

If you still want to wrap them though, but not as a smart_ptr I think you're going to have to just accept that there will be a lot of %smart_ptr - you could automate generating them though perhaps? You might be able to play games with modules, but I don't think that going to be easy or worth the effort.

like image 154
Flexo Avatar answered Oct 29 '22 18:10

Flexo