如何在包装 C++ 代码的 SWIG 中向目标语言(特别是 Python)添加替代构造函数

doe*_*toe 3 c++ python swig python-extensions

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

class X {
 public:
  X() {...}
  void init(T a) {...}
  ...
};
Run Code Online (Sandbox Code Playgroud)

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

X x;
x.init(a);
Run Code Online (Sandbox Code Playgroud)

在Python中我想做

x = X(a)
Run Code Online (Sandbox Code Playgroud)

我的解决方案是一个 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
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

这工作正常,但不是很令人满意:

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

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

m7t*_*hon 6

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

诚然,这看起来有点可疑,但它确实有效,并且本质上是 SWIG 文档中的一个示例

需要注意的是:

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

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