How to apply SWIG OUTPUT typemaps for class types in Python?

后端 未结 3 817
青春惊慌失措
青春惊慌失措 2020-12-17 19:52

I am having some trouble generating a Python wrapper around a C++ library using SWIG (version 3.0.6).

My issue relates to applying the OUTPUT typemap, specifically i

3条回答
  •  天涯浪人
    2020-12-17 20:09

    This question has appeared as unresolved for quite some time, so I thought that I better provide a solution to the question. The OUTPUT typemap only applies to simple types, so a solution is given by combining an in and an argout typemap.

    Consider the situation, where we have a C++ class SampleImpl implementing a C++ interface SampleBase, which is technically not an interface, since it involves the implementation of a virtual destructor. Suppose we have a static function, which returns an error code and an implementation of the interface. The latter as a reference to a pointer, which is the situation above.

    Interface header:

    // Sample.hpp
    #pragma once
    namespace Module {
      class SampleBase {
      public:
    #ifndef SWIG
        // Hint to the programmer to implement this function
        static int SampleCreate(SampleBase *&obj);
    #endif
        virtual ~SampleBase() = default;
      };
    }
    

    Implementation header:

    // Sample_impl.hpp
    #pragma once
    #include "Sample.hpp"
    
    namespace Module {
      class SampleImpl : public SampleBase {
      public:
        static int SampleCreate(Module::SampleBase *&obj);
    
        SampleImpl();
        virtual ~SampleImpl();
      private:
        float a;
      };
    }
    

    Implementation:

    // Sample_impl.cpp
    #include "Sample_impl.hpp"
    #include 
    
    namespace Module {
      int SampleImpl::SampleCreate(Module::SampleBase*& obj) {
        obj = (SampleBase*) new SampleImpl();
        return 0;
      }
      SampleImpl::SampleImpl() {
        printf("SampleImpl::SampleImpl()\n");
      }
    
      SampleImpl::~SampleImpl() {
        printf("SampleImpl::~SampleImpl()\n");
      }
    }
    

    SWIG interface (using argout typemap)

    // example.i
    %module example
    %{
      #define SWIG_FILE_WITH_INIT
      #include "Sample.hpp"
      #include "Sample_impl.hpp"
    %}
    
    %include "typemaps.i"
    
    %typemap(in, numinputs=0) Module::SampleBase *&obj (Module::SampleBase *temp) {
      $1 = &temp;
    }
    
    %typemap(argout) Module::SampleBase *& {
      PyObject* temp = NULL;
      if (!PyList_Check($result)) {
        temp = $result;
        $result = PyList_New(1);
        PyList_SetItem($result, 0, temp);
    
        // Create shadow object (do not use SWIG_POINTER_NEW)
        temp = SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
                 $descriptor(Module::SampleBase*),
                 SWIG_POINTER_OWN | 0);
    
        PyList_Append($result, temp);
        Py_DECREF(temp);
      }
    }
    

    Usage in Python

    import example
    
    // Creating specialization
    obj = example.SampleImpl()
    del obj
    
    // Creation of object using output typemap
    errorCode, obj = example.SampleImpl_SampleCreate()
    del obj
    

提交回复
热议问题