2012-06-13 52 views
4

我已經實現了一個簡單的C類,它使用結構中的函數指針來實現成員函數,並將指針傳遞給每個函數的第一個參數,類似於隱式的「this」在C++中的指針。如何讓SWIG自動將仿真的「this」指針包裝到C結構中?

%module mytest 
%{ 
typedef struct mytest mytest; 

struct mytest { 
    int data; 
    int (*func1)(mytest *,int); 
    void (*func2)(mytest *,int); 
}; 

int f1(mytest *me,int n) { return me->data + n; } 
void f2(mytest *me,int n) { me->data += n; } 

mytest *mytestNew(int n) { 
    mytest *me = (mytest*) malloc(sizeof(mytest)); 
    me->data = n; 
    me->func1 = f1; 
    me->func2 = f2; 
    return me; 
} 

%} 

typedef struct mytest mytest; 

struct mytest { 
    int data; 
    int func1(mytest *,int); 
    void func2(mytest *,int); 
}; 

extern mytest *mytestNew(int n); 

現在我的問題是,當接口創建任何語言,我在前端選擇,我拉閘具有與「this」指針明確地傳遞給對象,即使語言本身支持隱藏這個。

例如,假設我選擇Python。我必須做這樣的事情:

from mytest import * 
m = mytestNew(1) 
m.func1(m,0) 

當我真正想要的是像這樣做:

from mytest import * 
m = mytestNew(1) 
m.func1(0) 

我知道我可以只寫一些包裝代碼,但我的實際項目中,我在現有C代碼的許多對象中有很多功能,並且將其與我想支持的每種語言相乘,這只是太多的工作!有沒有辦法讓SWIG自動執行此操作?

+1

你的示例泄漏的方式 - 你想使用'%newobject mytestNew'來避免這種情況。出於好奇,有沒有第一個不使用C++的原因? – Flexo

回答

2

您可以在SWIG中以與語言無關的方式執行此操作,只需提供兩個類型圖即可,您可以在SWIG界面中指定一致的參數以及允許選擇性應用類型映射的定義。 (除非你想都指向mytest成爲「這個」指針由當然默認)

你需要的typemaps是:

// Make sure the wraqpped function doesn't expect an input for this: 
%typemap(in,numinputs=0) mytest *me "$1=NULL;" 
// Slightly abuse check typemap, but it needs to happen after the rest of the arguments have been set: 
%typemap(check) mytest *me { 
    $1 = arg1; 
} 

支票類型映射是不是真的打算這樣使用,但在從目標語言中提取參數之後並且在實際調用之前獲取代碼以進行注入是最簡單的方法。

您還可以在宏的幫助下簡化模塊,以避免必須編寫並保持函數指針與成員技巧之間的映射。我結束了test.h爲:

#ifdef SWIG 
#define MEMBER(name, args) name args 
#else 
#define MEMBER(name, args) (*name) args 
#endif 

typedef struct mytest mytest; 

struct mytest { 
    int data; 
    int MEMBER(func1,(mytest *me,int)); 
    void MEMBER(func2,(mytest *me,int)); 
}; 

和相應的接口文件(test.i):

%module test 

%{ 
#include "test.h" 

static int f1(mytest *me,int n) { return me->data + n; } 
static void f2(mytest *me,int n) { me->data += n; } 
%} 

%extend mytest { 
    mytest(int n) { 
    $self->data = n; 
    $self->func1 = f1; 
    $self->func2 = f2; 
    } 
} 

%typemap(in,numinputs=0) mytest *me "$1=NULL;" 
%typemap(check) mytest *me { 
    $1 = arg1; 
} 

%include "test.h" 

(此接口文件規定,「創建」「對象」構造究竟是如何一Java程序員會期望 - 你可以調用new並在後臺設置函數指針)

+0

謝謝,那就是訣竅!花了我一些時間來解決這個問題,但是「mytest * me」必須與我使用的任何類的第一個參數相匹配。另外,ifdef可以簡化一點:我使用「(* name)」和「name」,然後使用類似「int MEMBER(func1)(mytest * me,int);」 – Michael

+0

你可以使它匹配只是類型,而不是參數的名稱,但我認爲在某些時候你想要傳入一個不是「this」指針的函數,然後你會進入針對每種情況編寫特殊類型圖的業務,這種情況與僅使用一致名稱相比並不理想。 – Flexo