swig用变量扩展模板类

时间:2012-07-05 08:16:15

标签: c++ swig

我正在构建一个模板化类的Swig接口。在我的pyinterface.i文件中,我声明了

%template (myclass) MyClass<int>;

现在我要做的是将一个字段变量添加到我的新类中,我认为应该将其作为

%extend MyClass<int>{
    double x;
}

然而,这抱怨没有

  

myclass_get_x

方法定义。因此,如果我尝试通过将上述内容修改为:

来定义它
%extend MyClass<int>{
    double x;
    double MyClass<int>_get_x(MyClass<int> *f){
            return (*f)->x;
    }
}

然后我得到语法错误。

我尝试这样做:

%extend myclass{
    double x;
    double myclass_get_x(myclass *f){
            return (*f)->x;
    }
}

但这也会引发错误,因为myclass似乎还没有被理解。

1 个答案:

答案 0 :(得分:1)

使用%extend扩展类时,无法真正添加任何新成员变量,只能添加成员函数。如果你在%extend中执行此操作,它将假定存在get / set函数。

原因是新成员变量的存储(即内存)必须存在于某处,但没有明显的安全位置。你不能修改原始的C ++ class,因为如果你这样做,你会在其他一些预先编译的代码使用类的旧定义时最终得到未定义的行为。没有办法回顾性地应用新定义。您不能将它放在以目标语言生成的代理中,因为在目标语言中C ++类和代理的实例之间没有1:1的映射。 (考虑两个函数,它们都通过指针返回相同的全局实例,以获得如何发生这种情况的简单示例。)

如果你想实现get / set函数来做一些有用的事情(例如我在这里使用全局映射来存储额外的数据)你不想在%extend里面实现它们。例如,给定的测试.hh只是:

template <typename T>
struct Foo {};

您可以使用std::map来执行您尝试执行的操作,方法是将自己的gets和sets设置为包装器中的自由函数 - %{ %}直接传递代码:

%module test

%include "test.hh"

%{
#include "test.hh"
%}

%{
#include <map>
static std::map<Foo<int>*, double> extra_stuff;

const double& Foo_Sl_int_Sg__x_get(Foo<int>* f) {
  return extra_stuff[f];
}

void Foo_Sl_int_Sg__x_set(Foo<int>* f, const double& d) {
  extra_stuff[f] = d;
}
%}

%template(FooInt) Foo<int>;

%extend Foo<int> {
  double x;
}

get / set函数被SWIG自己的修改系统破坏,因为它是一个模板。我只是查看生成的包装器类,看看它们被调用了什么。 (我认为可能有一种更聪明的方法可以做到这一点,但我还是无法从文档中找到它)。如果它不是模板,那么函数的名称就会简单得多。

请注意,此处没有规定从此地图中删除条目 - 它将无限增长。 (例如,您可以通过提供在Object的生命周期结束时调用额外函数的类型映射来解决此问题)。你还需要注意线程。

由于您没有指定您使用的语言,我使用Java测试了上述代码:

public class run {
  public static void main(String[] argv) {
    System.loadLibrary("test");
    FooInt f = new FooInt();
    f.setX(0.1);
    System.out.println(f.getX());
  }
}

或者,如果您真的想要,您可以编写代码以确保目标语言中存在唯一的单个代理实例,方法是编写一个类型映射,检查是否已创建代理而不是始终创建代理,但是会引发引用计数和线程安全问题难以有效和一般地解决,这就是为什么它不是默认行为。

在很多情况下(例如目标语言中的迭代器)最简单的解决方法是使用%inline来声明和定义并同时包装所有提供所需功能的全新额外类。