2012-11-07 18 views

答えて

10

私は同じ問題に直面しました。 SWIGが間もなくC++ 11のenum classをサポートすることを願っています。

ここ構造で列挙型を入れてSWIGを説得するハックです:.cppコードで

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

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

あなたが今MyEnum::Value1を使用する必要がありますし、PythonコードでそれがMyEnum.Value1です。畳み込まれているにもかかわらず、typedefは、すべての列挙型を使用する既存のコードを変更する必要がなく、SWIG%名前の変更により、SWIGラッパーで列挙型の名前が同じになります。

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

それはかなりではない、と私はよりよい解決策を見てみたい:

はPythonでは、あなたは少しのコードで値を列挙することができます。

+0

うん、私はこのような何かを考えていたが、あなたの答えはいくつかのパターンを使用する準備ができて感謝しています。上記の 'sizeof'問題についてもう少し説明してください。私がそれを得ていないので、どんなコードが正確に壊れる可能性があります。 – unkulunkulu

+0

その部分を削除します。実装を見つけようと思っていたときに検討していたものでしたが、再訪しただけで問題にはなりませんでした。 –

2

私はあなたが探しているかなり確信している...
タイプマップ:タイプ処理は、ラッパーコード生成に非常に中心的であるので、SWIGは、それが完全に定義された(または再定義)ユーザーがすることができます。これを行うために、特別な%typemap指示が使用されます。 (SWIG Doc2.0)

ここでタイプマップについて必要な情報はすべて、SWIGのドキュメントに関するリンクです。 http://www.swig.org/Doc2.0/Typemaps.html#Typemaps_nn2

typemapを使用すると、SWIGにC++ enumを必要な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を作成します。中間モジュールのPyDictを公開されたモジュールに結びつけるために、そこには%pythoncodeグルーがあります。 (私は、_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 Nice解決策。私はそれを少し拡張して、キーのドット補完をサポートする辞書をインポートし、 'x = _test.x'を' x = dotdict(_test.x) 'に置き換え、'%pythoncode%{dictsからimport { } '' PYTHON_ENUM'マクロの前に。 –

関連する問題