如何在 SWIG 包装 C++ 代码中向目标语言(特别是 Python)添加替代构造函数
How to add an alternative constructor to the target language (specifically Python) in SWIG wrapping C++ code
我正在使用 SWIG 创建 Python 某些我无法更改的 C++ 代码的接口。其中一个 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 如何在内部包装构造函数
- 它完全取决于目标语言
这似乎是一个比较常见的用例,所以有人知道是否有标准方法吗?
你可以试试这样:
%ignore X::X();
%extend X {
X(T a) {
init(a);
}
};
这将隐藏默认的无参数构造函数并添加采用 T
的新构造函数
缺点是如果被忽略的一个正在做某事,那么您需要将其复制到这个新的,因为您不能从同一个 class 构造函数中调用其他构造函数(除非您使用的是 C++11 )
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 works with both C and C++ code. It does not modify the underlying object in any way---the extensions only show up in the Python interface.
所以这真正做的是创建一个方法(实际上甚至不是 class 方法)来创建 X
的新实例,在其上调用 init(a)
和 returns它。由于语法有点类似于构造函数,SWIG 将这样包装它。
我正在使用 SWIG 创建 Python 某些我无法更改的 C++ 代码的接口。其中一个 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 如何在内部包装构造函数
- 它完全取决于目标语言
这似乎是一个比较常见的用例,所以有人知道是否有标准方法吗?
你可以试试这样:
%ignore X::X();
%extend X {
X(T a) {
init(a);
}
};
这将隐藏默认的无参数构造函数并添加采用 T
缺点是如果被忽略的一个正在做某事,那么您需要将其复制到这个新的,因为您不能从同一个 class 构造函数中调用其他构造函数(除非您使用的是 C++11 )
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 works with both C and C++ code. It does not modify the underlying object in any way---the extensions only show up in the Python interface.
所以这真正做的是创建一个方法(实际上甚至不是 class 方法)来创建 X
的新实例,在其上调用 init(a)
和 returns它。由于语法有点类似于构造函数,SWIG 将这样包装它。