2012-11-07 67 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'宏之前。 –