2012-11-07 13 views

Odpowiedz

10

Napotkałem ten sam problem. Mam nadzieję, że SWIG wkrótce obsługuje C++ 11: enum class.

Oto hack, który przekonuje SWIG umieścić teksty stałe w strukturze:

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

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

W .cpp kod, który teraz musi używać MyEnum::Value1 w kodzie Pythona to MyEnum.Value1. Chociaż zawikłany, typedef uniemożliwia zmianę istniejącego kodu, który używa enum wszędzie, a zmiana nazwy SWIG% sprawia, że ​​enum mają tę samą nazwę w opakowaniu SWIG.

W Pythonie można wyliczyć wartości z odrobiną kodu:

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

To nie jest ładna, i chciałbym zobaczyć lepsze rozwiązanie.

+0

Tak, myślałem o czymś takim, ale odpowiedź zapewnia jakąś gotową do wykorzystania wzoru, dzięki. Czy możesz wyjaśnić nieco więcej na temat wspomnianego problemu 'sizeof'? Który kod może się dokładnie złamać, ponieważ nie rozumiem tego. – unkulunkulu

+0

Usuwam tę część.To było coś, co rozważałem, próbując znaleźć implementację, ale po prostu wróciłem do tego i nie było to naprawdę problemem. –

2

jestem całkiem pewny szukasz są ...
typemaps: Ponieważ rodzaj manipulacja jest tak centralny do generowania kodu wrapper, SWIG pozwala mu być całkowicie zdefiniowana (lub nowo) przez użytkownika. Aby to zrobić, używana jest specjalna dyrektywa% typemap. (SWIG Doc2.0)

Aby uzyskać wszystkie informacje, jakich można potrzebować w przypadku map typów, tutaj znajduje się link do dokumentacji SWIG na ten temat. http://www.swig.org/Doc2.0/Typemaps.html#Typemaps_nn2

Typemaps powinno umożliwić informowanie SWIG o konwersji wyrażeń w języku C++ na żądane obiekty Pythona.

+0

@ Flexo, tbh, nie wiedziałem o typemapach, jestem nowy w SWIG, po prostu użyli go w projekcie w niektórych ciemniejszych częściach, działało i nikt się tym nie przejmował, ale potem zdecydowałem się go rozszerzyć kawałek. – unkulunkulu

5

Możemy stworzyć coś, co pozwoli ci wyliczyć w Pythonie, przy stosunkowo niewielkiej ingerencji w nagłówki C++, które zawija. Na przykład, jeśli mamy plik nagłówka:

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

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

PYTHON_ENUM(SomeOtherName) { 
    woof, 
    moo 
}; 

Rozszerza się być zwykłym enum w C++, ale jest wystarczający jako plik nagłówka narazić członków enum w Pythonie.

Używając %typemap(constcode) możemy wprowadzić dodatkowe elementy do naszego modułu Pythona dla wyliczenia, ale musimy znać nazwę enum, aby to zrobić; Obiekt typu swiss dla SWIG jest taki, jak gdyby był to int. Dlatego używamy odrobiny hackowania w naszym makrze PYTHON_ENUM, aby zapisać nazwę wyliczenia w niestandardowej mapie typów.

%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" 

Spowoduje to utworzenie PyDict w module pośrednim dla każdego wyliczenia z parami klucz/wartość. Jest tam również pewna ilość kleju %pythoncode, aby związać PyDict w module pośrednim z eksponowanym modułem. (Nie jestem pewien, jak odnieść się do modułu pośredniego po nazwie w nim, inne niż na stałe oznaczony jako _test - zmiana w razie potrzeby).

Wystarcza to, że mogę użyć go jako:

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

Wygląda więc na to, że trudność wynika z tego, że SWIG jest celowo celowy, wydaje się, że nie miał na myśli przeniesienia refleksji C/C++ do języków skryptowych, tylko generowania interfejsu. Wygląda na to, że będę musiał pójść z rozwiązaniem Marka Tolonena po prostu dlatego, że niewielu zrozumie twoje, chociaż jestem na krawędzi zrozumienia tego w tej chwili: D Dziękuję za przykład wypróbowania rzeczy z mapami. – unkulunkulu

+0

@unkulunkulu - ogólnie SWIG stara się zrobić wszystko, co możliwe w C (lub C++), ale błądzenie poza tym wydaje się być trudniejsze. – Flexo

+0

@Flexo Ładne rozwiązanie. Rozszerzyłem go nieco, aby zaimportować słownik, który obsługuje uzupełnianie kropek na klawiszach i zastąpił 'x = _test.x' za pomocą' x = dotdict (_test.x) 'i dodał'% pythoncode% {from dicts import dotdict% } 'przed makrem' PYTHON_ENUM'. –

Powiązane problemy