2016-11-15 97 views
0

創建typedefd類型的變量我有痛飲項目設置生成Python代碼。我有一個std::stringtypedefMessage一個say(Message)功能。我可以用python中的字符串調用say。我希望能夠創建類型爲Message的變量,並且Message類型被導出到庫中,但不是python包裝器。下面是我的文件:在痛飲

test.h

#include <string> 
#include <iostream> 

typedef std::string Message 
void say(Message s); 

TEST.CPP

#include "test.h" 

void say(Message s) 
{ 
    std::cout << s << std::endl; 
} 

test.i

%module test 
%{ 
#include "test.h" 
%} 

typedef std::string Message; 
%include "std_string.i" 
%include "test.h" 

Python的例子

import test 
test.say('a') 
# >>> a 

# What I want to be able to do 
msg = test.Message('a') 
# >>> Traceback (most recent call last): 
# >>> File "<stdin>", line 1, in <module> 
# >>> AttributeError: module 'test' has no attribute 'Message' 

我的實際使用案例還涉及對其他類型(主要是枚舉)的typedefs,如果這些案例採取了不同的處理方式,我很好奇。我相信我可以將對象包裝在SWIG綁定的類中,然後修改SWIG生成的類(或者可以使用SWIG類型映射),但是我覺得這是一個迂迴解決方案,我認爲這是一種常見的情況。

我認爲這可能是訪問string標題中的代碼的問題,但如果我嘗試敲入類似int之類的東西,我會遇到同樣的問題。

我的最好的方法,到目前爲止已被包裝的模板:

template<typename T> 
class Wrapper 
{ 
public: 
    Wrapper(T x) : data(x){}; 
    T data; 
    T operator()() { return data; }; 
}; 

而且相應的%template指令在test.i

%template(Message) Wrapper<std::string>; 

不幸的是,這似乎有幾個缺點至今:

  • 你必須實際LY打電話operator(),即需要test.Message('a')()被稱爲
  • 您需要可以選用一些條件編譯或名稱,包裝的東西從不同的typedef;否則,test.say將不接受包裝或字符串,因此根本無法使用。
  • 它似乎並不與施工錯誤枚舉工作。

我也認爲我可能很聰明,並改變operator*只是返回正在包裝,但它看起來像SWIG包裹什麼是返回無論如何。

+0

我建議你使用'const char *',因爲'std :: string'不是'POC'類型,並且內存分配在堆上,不管它是調試版本還是發行版本,其操作都是不同的。我預計通過包含'%include「std_string.i」'你可以創建一個'std :: string'實例。你有沒有嘗試過使用這個參數? –

+0

我的預期是錯誤的,但我仍然建議您在界面上使用POC類型。 –

+0

我希望能夠將'%include std_string.i'或%import std_string.i'中的字符串實例化爲'std_string.i'模板'string'作爲'basic_string '。奇怪的是,這些似乎都沒有導入一個可以創建實例的對象。也許這是因爲SWIG似乎通過將字符串映射到目標語言字符串來處理字符串? – danielunderwood

回答

0

一般在痛飲類型定義應該「只是工作」。 (有一個例外,我知道他們經常不按預期行爲和實例化模板時的,但在這裏,這不是一個問題。)

在您的例子我覺得你的問題很簡單typedef的知名度相對於std::string的定義。如果你改變你的。我的文件是:

%module test 
%{ 
#include "test.h" 
%} 

%include "std_string.i" 
typedef std::string Message; 
%include "test.h" 

還是

%module test 
%{ 
#include "test.h" 
%} 

%include "std_string.i" 
%include "test.h" 

然後我會期待你的示例代碼工作。

根據std::string vs const char*,對於Python用戶應該有非常小的可觀察到的行爲差異。 Python的本地字符串類型將被正確自動地轉換爲任何一種,所以我堅持的規則是,如果您使用的是C++,那麼使用C++類型,除非有一個重要的原因。 POD-ness(或缺乏)不太可能成爲界面的昂貴部分,甚至不太可能成爲性能的瓶頸。

+0

這似乎給了我相同的結果。當我有權訪問typedef別名的對象時,typedefs似乎工作。在字符串的情況下,我能夠將字符串傳遞給代碼並使其工作,但無法實例化別名類型。也許一個字符串是一個壞例子,因爲它在大多數地方都可用。考慮'class C {...}; typedef C CAlias;'如果我在接口中有'C'聲明,我可以實例化一個類'C'的對象並傳遞它,但是SWIG不允許我實例化一個類'CAlias'並將其稱爲它。這是預期的行爲還是我錯過了什麼? – danielunderwood

+1

這是預期的行爲 - 類型定義在C和C++中是'弱'的,所以這個(大部分)反映了語言那一邊的行爲。如果你真的想要,你可以使用'%pythoncode%{CAlias = C%}'來使'CAlias'成爲一種Python類型,但是它並沒有太大的收穫。如果你想'CAlias'成爲一個強類型的Python事物,你會想使用類似'BOOST_STRONG_TYPEDEF'的東西,並且我可以擴展來談論包裝。我懷疑,如果typedef的目的只是友好名稱,那麼你可能想要的所有內容都是SWIG的'%rename'指令來重命名基礎類型。 – Flexo

+0

'%pythoncode'的方式工作得很好,但在語言之間並不是真正可移植的。具體來說,我意識到'typedef'不會翻譯成很多語言。 '%rename'很好地與我對枚舉的一些示例代碼很好地工作,但對於我測試過的字符串沒有做任何事情。我認爲我的最佳選擇是將「Message」變成完整的類,或者只是將文檔直接用於目標語言。如果我大量使用typedefs,而不是在少數情況下,強類型定義可能是一個好主意。 – danielunderwood