2012-11-07 68 views

回答

10

我面臨同樣的問題。我希望SWIG很快支持C++ 11的enum class

下面是說服夜風把枚舉結構中的一個黑客:

#ifdef SWIG 
%rename(MyEnum) MyEnumNS; 
#endif 

struct MyEnumNS 
{ 
    enum Value { Value1, Value2, Value3 }; 
}; 
typedef MyEnumNS::Value MyEnum; 

.cpp代碼,你現在必須使用MyEnum::Value1和Python代碼是MyEnum.Value1。雖然令人費解,但typedef可以防止必須更改在任何地方使用枚舉的現有代碼,並且SWIG%重命名使枚舉在SWIG包裝器中具有相同的名稱。

在Python中,你可以用一點代碼枚舉值:

def values(enum): 
    return [(k,v) for k,v in vars(enum).items() if isinstance(v,int)] 

這不是漂亮,我喜歡看到一個更好的解決方案。

+0

是啊,我在想這樣的事情,但你的答案提供了一些準備使用的圖案,謝謝。你能解釋一下上面提到的'sizeof'問題嗎?什麼代碼可以完全打破,因爲我不太明白。 – unkulunkulu

+0

我將刪除該部分。這是我在試圖找到實現時正在考慮的事情,但我只是重新訪問它,並不是一個真正的問題。 –

2

我敢肯定,你要找的是...
typemaps:由於類型的處理是如此重要的包裝代碼生成,SWIG使得它能夠被用戶完全定義(或重定義)。爲此,使用特殊的%typemap指令。 (SWIG Doc2.0)

對於您可能需要的有關typemaps的所有信息,請參閱SWIG文檔的鏈接。 http://www.swig.org/Doc2.0/Typemaps.html#Typemaps_nn2

Typemaps應該允許您告訴SWIG將C++枚舉轉換爲您想要的python對象。

+0

@Flexo,tbh,我不知道類型圖,我是SWIG的新手,他們只是在項目的一些較暗的部分使用它,它工作,沒有人關心,但後來我決定擴展它位。 – unkulunkulu

5

我們可以做一些讓你在Python中枚舉的東西,相對較少入侵它所包裝的C++頭文件。例如,如果我們有一個頭文件:

#ifndef PYTHON_ENUM 
#define PYTHON_ENUM(x) enum x 
#endif 

PYTHON_ENUM(TestName) { 
    foo=1, 
    bar=2 
}; 

PYTHON_ENUM(SomeOtherName) { 
    woof, 
    moo 
}; 

它擴展到只是在C++中常規的枚舉,但足以作爲一個頭文件暴露在Python枚舉成員。

使用%typemap(constcode)我們可以在我們的Python模塊中爲enum注入一些額外的東西,但我們需要知道枚舉的名稱來完成此操作; SWIG typeinfo對象就好像它是一個int。因此,我們在我們的PYTHON_ENUM宏中使用了一些黑客技術來將枚舉的名稱存儲在自定義的類型映射中。

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

%typemap(constcode) int { 
    PyObject *val = PyInt_FromLong(($type)($value)); 
    SWIG_Python_SetConstant(d, "$1", val); 
    const char *name = "$typemap(enum_realname,$1_type)"; 
    PyObject *e = PyDict_GetItemString(d, name); 
    if (!e) PyDict_SetItemString(d, name, e = PyDict_New()); 
    PyDict_SetItemString(e, "$value", val); 
} 
#define PYTHON_ENUM(x) \ 
     %typemap(enum_realname) int "x"; \ 
     %pythoncode %{ \ 
     x = _test.x\ 
     %} \ 
     enum x 

%include "test.h" 

這將在每個具有鍵/值對的枚舉的中間模塊中創建一個PyDict。還有一些%pythoncode粘合劑將中間模塊中的PyDict綁定到暴露的模塊中。 (我不知道如何通過名稱引用中間模塊,除了硬編碼爲_test - 根據需要更改)。

這是足夠的,我就可以使用它作爲:

Python 2.7.3 (default, Aug 1 2012, 05:16:07) 
[GCC 4.6.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import test 
>>> print test.SomeOtherName 
{'woof': 0, 'moo': 1} 
>>> print test.TestName 
{'foo': 1, 'bar': 2} 
>>> 
+0

所以看起來這很難,因爲SWIG的目的很簡單,似乎他們沒有考慮將C/C++反射帶入腳本語言,只是界面生成。看起來我不得不採用Mark Tolonen的解決方案,因爲很少有人會理解你的,儘管我現在正在理解它:D謝謝你嘗試使用類型映射的例子。 – unkulunkulu

+0

@unkulunkulu - 通常SWIG會盡力讓您在C(或C++)中儘可能做到儘可能簡單,但除此之外,這往往會更困難。 – Flexo

+0

@Flexo尼斯解決方案。我擴展了一下導入一個字典,它支持鍵完成,並用'x = dotdict(_test.x)'替換'x = _test.x'並添加了一個'%pythoncode%{from dicts import dotdict% }在'PYTHON_ENUM'宏之前。 –