CYTHON, как я могу передать функцию-член в качестве обратного вызова нативному

Я могу получить нормальные обратные вызовы от родного до Cython.

Но как настроить функцию-член для обратного вызова в cython.

Мой sampleCallback.h файл:

 namespace mango {
 class sampleCalls { 
 public:
     typedef void (*Callback)(char *name);

     sampleCalls(Callback method, char *name);
     void execute();
 private:
     Callback _method;
     char *_key;
 }; }

И мой файл sampleCallback.cpp содержит простую реализацию:

 namespace mango {
        sampleCalls::sampleCalls(Callback method, char *name) {
                _method = method;
                _key = name;
        };
        void sampleCalls::execute()
        {
                return _method(_key);
        };
}

Теперь я написал очень простую оболочку cython callback.pyx:

ctypedef void (*Callback)(char *name)

cdef extern from "sampleCallback.h" namespace "mango" :
        cdef cppclass sampleCalls:
                sampleCalls(Callback method, char *name)
                void execute()

cdef void callbackCY(char* name):
        print "I AM ", name

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(callbackCY, "BATMAN")

    def  execute(self):
            self.sc.execute()

Это строится и работает нормально, когда я запускаю простой код Python:

import callback
cb = callback.pyCallback()
cb.execute()

Это прекрасно работает и выводит :: I AM BATMAN

Но это не то, чего я хочу. Я хочу, чтобы функция обратного вызова была частью определенного класса cython, поэтому я реализовал класс примерно так:

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
        self.sc = new sampleCalls(cb, "BATMAN")

    def  execute(self):
        self.sc.execute()

    cdef void cb(self, char* name):
        print name, " WINS"

Это, конечно, не работает, так как прототип обратного вызова не совпадает.

КАК ЭТО ПРАВИЛЬНО СДЕЛАТЬ?

Я также пробовал std::bind что-то вроде этого ::

cdef place1 "std::placeholder1"
cdef bind_py "std::bind"

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
        self.sc = new sampleCalls(bind_py(self.cb, self, place1),     "BATMAN")

Это тоже не работает. Ошибка ::

Error compiling Cython file:
------------------------------------------------------------
...
cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(bind_py(self.cb, self, place1), "BATMAN")
                                   ^
------------------------------------------------------------

callback.pyx:19:40: Cannot convert 'void (pyCallback, char *)' to Python object

Error compiling Cython file:
------------------------------------------------------------
...
cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(bind_py(self.cb, self, place1), "BATMAN")
                              ^
------------------------------------------------------------

callback.pyx:19:35: Cannot convert Python object to 'Callback'

Как я могу это сделать?? Пожалуйста помоги.


person wolv3r1n3    schedule 14.05.2018    source источник
comment
см. вторую часть этого ответа для подхода, использующего Ctypes. Если вы можете изменить подпись на C++ std::function, см. этот ответ   -  person DavidW    schedule 14.05.2018
comment
Здравствуйте, DavidW, я попытался реализовать вторую часть вашего ответа. ftype = ctypes.CFUNCTYPE(c_void, POINTER(c_char)) f = ftype(self.internalCallback) Но я не уверен, что делать с 3-й строкой cdef someFunctionPointer cy_f_ptr = (‹someFunctionPointer*›‹size_t›ctypes.addressof(f) )[0] Как мне это объявить? Что я должен заменить someFunctionPointer на ? Предполагается, что это «идентификатор типа», верно?   -  person wolv3r1n3    schedule 31.05.2018
comment
someFunctionPointer — это ctypedef указателя функции C. например сделайте ctypedef void (*someFunctionPointer)(char*), чтобы someFunctionPointer был указателем на функцию, которая принимает char* и ничего не возвращает.   -  person DavidW    schedule 01.06.2018