Mar*_*nen 10
我遇到了同样的问题.我希望SWIG很快支持C++ 11 enum class.
这是一个说服SWIG将枚举放入结构的黑客:
#ifdef SWIG
%rename(MyEnum) MyEnumNS;
#endif
struct MyEnumNS
{
enum Value { Value1, Value2, Value3 };
};
typedef MyEnumNS::Value MyEnum;
Run Code Online (Sandbox Code Playgroud)
在.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)]
Run Code Online (Sandbox Code Playgroud)
它不漂亮,我很想看到更好的解决方案.
我们可以制作一些东西,让你在Python中枚举它,对它包装的C++头文件的入侵相对较少.例如,如果我们有一个头文件:
#ifndef PYTHON_ENUM
#define PYTHON_ENUM(x) enum x
#endif
PYTHON_ENUM(TestName) {
foo=1,
bar=2
};
PYTHON_ENUM(SomeOtherName) {
woof,
moo
};
Run Code Online (Sandbox Code Playgroud)
它扩展为C++中的常规枚举,但足以作为头文件在Python中公开枚举成员.
使用%typemap(constcode)我们可以在我们的Python模块中为枚举注入一些额外的东西,但我们需要知道枚举的名称来做到这一点; 它的SWIG typeinfo对象就好像是一个int.因此,我们在PYTHON_ENUM宏中使用一些hack 来将枚举的名称存储在自定义类型映射中.
%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"
Run Code Online (Sandbox Code Playgroud)
这会在中间模块中为每个具有键/值对的枚举创建一个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}
>>>
Run Code Online (Sandbox Code Playgroud)