2015-07-15 15 views
10

Pytanie

Czy istnieje sposób na stworzenie opakowania Pythona dla C++ w klasie C++ z szablonami? (tj. zrób dokładnie to, co jest tutaj pokazane, ale z szablonami: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#create-cython-wrapper-class).Cython: szablony w wrapperach klasy Pythona

Wiem o rozwiązaniu typu topionego (https://groups.google.com/forum/#!topic/cython-users/qQpMo3hGQqI), ale to nie pozwala na instatiate klas takich jak vector<vector<int>>: typy topionego mają, całkiem nieoczekiwanie, nie pojęcie rekursji.

Parafrazując

Co chciałbym osiągnąć to za zawiniętej klasy takich jak:

cdef extern from "header.h": 
    cdef cppclass Foo[T]: 
     Foo(T param) 
     # ... 

stworzyć prosty wrapper Pythona:

cdef class PyFoo[T]: # I know the '[T]' can't be here, it's a wish 
    cdef Foo[T] *thisptr 
    def __cinit__(self, param): 
     self.thisptr = new Foo[T](param) 
    # ... 

jestem całkiem pewny, że nie robi Cython Wsparcie to samo w sobie, ale może ktoś może wymyślić obejście tego problemu. Nie szukam idiomatycznych lub fajnych przykładów, zastanawiam się, czy to możliwe w jakikolwiek sposób.

+1

Co powiesz na to, żeby uruchomić go przez jakieś podstawianie ciągów znaków w celu wygenerowania innego pliku źródłowego dla każdego 'T'? – DavidW

+0

Więc, w gruncie rzeczy, co robi kompilator C++ dla szablonów, ale dla wrapperów cytoników? Myślałem o tym. Jest to z pewnością opcja, którą rozważam, chociaż w pewien sposób rozszerza ona kompilator cythonu i sporo pracy. – piotrMocz

+0

Myślę, że miałem na myśli coś znacznie prostszego: 1) stwórz plik zawierający 'cdef class PyFoo_ {T}: cdef Foo [{T}] * thisptr' itp. 2) Wygeneruj kilka plików cython, wykonując' .format (T = 'std :: vector ') 'i zapisywanie wyników. 3) Dołącz te pliki do głównego pliku Cythona (synatax 'include" filename.pxi "'). Oczywiście musisz wybrać klasy do ręcznego wygenerowania, ale zawsze musisz to zrobić. – DavidW

Odpowiedz

7

Jak już powiedziałeś, Cython tak naprawdę nie obsługuje tego.

Myślę, że jak na razie najprostszym sposobem jest ręczne wygenerowanie pęczku plików Cythona za pomocą podstawiania ciągów znaków. Zacznij z „foowrapper.pxi.src” (nazwa pliku, jak chcesz ...):

cdef class PyFoo_{T}: 
    cdef Foo[{T}] *thisptr 
    def __cinit__(self, param): 
    self.thisptr = new Foo[{T}](param) 
    # etc 

Następnie uruchomić go za pomocą prostego programu (może być równie dobrze Python), aby załadować plik, wykonaj Zastąp ciąg i zapisz plik ponownie pod nową nazwą. Kluczem jest to po prostu:

output = code.format(T=T) # where T is a string with a C++ class name 
       # e.g. "int" or "std::vector<double>" 

(Jest oczywiście trochę kodu odnoszące się do załadunku i zapisywanie że mam pomijane z lenistwa)

Następnie w Cython plik, który po prostu „to” THE wygenerowane pliki dla każdej klasy. „Dołącz” polecenia w Cython jest dosłownym tekstowy include (jak preprocesora C) i oczekuje PXI plik:

cdef extern from "header.h": 
    cdef cppclass Foo[T]: 
     Foo(T param) 
     # ... 

include "foowrapper_int.pxi" 
include "foowrapper_vectordouble.pxi 
# etc 

trzeba wybrać zajęcia generować w czasie kompilacji, ale jest to nieuniknione (szablony są funkcją czasu kompilacji), więc nigdy nie będziesz w stanie generować ich dynamicznie ze środowiska skryptów w Pythonie, ponieważ odpowiednia klasa C++ nie zostanie wygenerowana.

Inne opcje

Kilka innych opcji warto krótki uwagę. Po pierwsze, możesz odziedziczyć Foo<T> z klasy bazowej (na przykład FooBase), która nie zależy od parametru szablonu. Wówczas będziesz owijał FooBase w Cython (generując funkcje podobne do konstruktorów dla spraw, które Cię interesują). Jest to możliwe tylko wtedy, gdy funkcje, które chcesz wywołać, nie mają argumentów zależnych od typu szablonu. Oczywiście wiąże się to również ze zmianą kodu C++.

Opcja przekroju polega na spojrzeniu na inny sposób owijania. Boost Python z pewnością będzie to wspierać natywnie (ale ma swoje wady). Wyobrażam sobie, że SIP/SWIG również sobie poradzą (ale nie wiem).Jeśli to konieczne, możesz dość łatwo wymieszać i dopasować je do Cython (importując wygenerowany moduł zawierający klasy szablonów).

+0

Wydaje mi się, że w moich badaniach brakowało mi Boost Pythona, muszę go bliżej przyjrzeć. Ponadto: wspaniała odpowiedź, naprawdę wyjaśnia wiele rzeczy, dziękuję. – piotrMocz