2012-07-05 40 views
2

我正在構建一個模板類的Swig接口。在我pyinterface.i文件,我宣佈swig擴展一個模板類與變量

%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的似乎並不被十分明瞭。

+0

與我的回答無關,但是'myclass * f'的意思是這裏像是一個'this'指針嗎?你不需要明確地寫出這個參數,但是你需要使用'$ self'而不是'this'來加上'%extend'。 – Flexo

+0

是的,這基本上是我試圖使用它。我認爲這種格式是使用'$ self'而不是'this'的替代方案。也許我不能這樣做。 – thebigdog

回答

1

當你用%extend擴展一個類時,你不能真的添加任何新的成員變量,只有成員函數。如果你在%extend中這樣做,它將假設存在一個get/set函數。

其原因是新成員變量的存儲(即內存)將不得不在某個地方居住,但沒有明顯的安全位置。你不能修改原來的C++ class,因爲如果你這樣做的話,當其他一些預編譯的代碼使用該類的舊定義時,最終會導致未定義的行爲;沒有辦法追溯應用新的定義。您無法將其放入以目標語言生成的代理中,因爲在目標語言中C++類和代理之間沒有1:1映射。 (考慮兩個函數,這兩個函數都可以通過指針返回同一個全局實例,以瞭解可能發生這種情況的簡單示例)。

如果你想實現get/set函數來做一些有用的事情(例如,在這裏我使用全局地圖來存儲額外的數據),你不想在%extend裏實現它們。例如,給出test.hh和只是 - :

%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; 
} 

template <typename T> 
struct Foo {}; 

可以使用std::map做你想做什麼寫你自己的獲取和設置在包裝免費功能%{ %}只是徑直通過代碼

ge由於它是一個模板,t/set函數被SWIG自己的mangling系統破壞。我只是看着生成的包裝類,看看他們被稱爲。 (我認爲可能有更聰明的做法,但我無法從文檔中找出它)。如果它不是模板,那麼函數的名稱就會簡單得多。

請注意,此處沒有規定從此地圖刪除條目 - 它只會無限增長。 (你可以通過提供一個在對象生命週期結束時調用額外函數的類型映射來解決這個問題)。你還需要小心線程。

既然你沒有指定你使用的是什麼語言我測試與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來聲明和定義並全部包含一個全新的額外類,它提供了您想要的功能。

+0

謝謝Flexo,優秀的答案!從我認爲會是「你忘記了逗號」類型的問題中學到了很多東西。 – thebigdog

+0

雖然我對一件事感到困惑: **您無法將其放入以目標語言生成的代理中,因爲在目標語言中C++類和代理的實例之間不存在1:1映射。 (考慮兩個函數都可以通過指針返回相同的全局實例,以瞭解這種情況可能發生的簡單示例)。** 您能提供一個參考來進一步解釋缺少1:1映射嗎?從我迄今爲止讀到的有關swig的內容來看,這也是令人驚訝的。我相信你是對的,我只是不知道爲什麼。 – thebigdog

+0

@thebigdog SWIG只處理函數的定義而不是聲明。因此,很難證明一個函數是否可以返回兩次相同的事物。這就是爲什麼你需要使用'%newobject'來告訴SWIG關於創建新對象的函數的所有權語義。如果代理不擁有對象,那麼可能會在對象的生命週期中創建多個對象。在很難證明某件事是同一個對象的情況下 - 如果你再次調用'new',然後'delete',然後'new',可以合理地重用相同的地址。 – Flexo