如何在SWIG包装C ++代码

时间:2015-11-06 10:26:53

标签: python c++ swig python-extensions

我正在使用SWIG创建一些我无法更改的C ++代码的Python接口。其中一个C ++类有一个构造函数,它创建一个暂时无法使用的部分初始化对象,首先必须在其上调用初始化函数。我想在Python中通过提供一个替代构造函数来解决这个问题,该构造函数同时处理这两件事(获取和初始化)。让我们说在C ++中我有

class X {
 public:
  X() {...}
  void init(T a) {...}
  ...
};

在C ++中,我必须将X实例化为

X x;
x.init(a);

在Python中我想做

x = X(a)

我的解决方案是一个hack,它取决于目标语言和SWIG生成包装器代码的具体方式:在我的.i文件中我有

%inline %{
X* new_X(T a) {
  X* ret = new X();
  ret->init(a);
  return ret;
}

%nodefaultctor X;
class X {
 public:
  ...
  %extend {
    %pythoncode {
      def __init__(self, *args):
          this = _modulename.new_X(*args)
          try:
            self.this.append(this)
          except:
            self.this = this
    }
  }
};

这种方法很好,但不是很令人满意:

  • 这取决于SWIG如何在内部包装构造函数
  • 完全符合目标语言

这似乎是一个相对常见的用例,所以有人知道是否有标准方法吗?

2 个答案:

答案 0 :(得分:2)

V-master的当前答案不能正常工作。但它可以起作用:

%ignore X::X();

// declaration of class X, e.g. %include X.h

%extend X {
    X(T a) {
        X* newX = new X();
        newX->init(a);
        return newX;
    }
};

不可否认,这看起来有点可疑,但它确实有效,而且基本上是SWIG文档here中的一个例子。

重要的是要注意:

  

%extend适用于C和C ++代码。它不会以任何方式修改底层对象---扩展只出现在Python界面中。

所以这真正做的是创建一个方法(实际上甚至不是一个类方法),创建一个X的新实例,在其上调用init(a)并返回它。因为语法有点类似于构造函数,所以SWIG会将其包装起来。

答案 1 :(得分:1)

你可以尝试这样的事情:

class studyInformationType extends AbstractType
{
     public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('languages', 'collection', array('type' => new languageInformationType()))
    ;
    }

这将隐藏默认的无参数构造函数并添加新的%ignore X::X(); %extend X { X(T a) { init(a); } };

缺点是如果忽略一个人正在做某事,那么你需要将其复制到这个新的,因为你不能从同一个类构造函数中调用其他构造函数(除非你使用的是C ++ 11)