Here are my settings: I have next c++ class which I want to wrap:
// Foo.h
class Foo
{
public:
typedef int MyType;
typedef int ArgType1;
typedef int ArgType2;
...
typedef MyType (*FooFunction) (ArgType1 a, ArgType2 b);
...
void setFooFunction(FooFunction f);
Example of using this class in c++:
#include "Foo.h"
...
int fooFun(int a, int b)
{
if (a > b) return a;
else return b;
}
...
int main(int argc, char **argv)
{
...
fooObj->setFooFunction(&fooFun);
...
}
Cython wrapper:
# .pyx
cdef extern from "Foo.h":
cdef cppclass Foo:
void setFooFunction(int *) except +
def bar(fooFun):
...
fooobj.setFooFunction(fooFun)
...
And I want to be able to do this:
# python file
...
def pyfun(x, y):
return x + y
...
def main():
bar(pyfun)
I'm not familiar with Cython completely, but I've already tried to do some magic and it doesn't work:
# .pyx
cdef extern from "Foo.h":
cdef cppclass Foo:
void setFooFunction(int *) except +
ctypedef int (*myFun) (int, int)
def bar(fooFun):
cdef myFun funpointer
funpointer = (<myFun*><size_t>id(smoothfun))[0]
...
fooobj.setFooFunction(<int*>fooFun)
...
Is it even possible to do such things?
You can't easily: a C++ function pointer just stores the location in memory where the code for that function begins (or something similar, implementation specific) while a Python function is a full Python object with a dictionary storing the bytecode, (possibly the uncompiled Python code), documentation strings and a few other bits. It also isn't in a form that the machine can run on its own - it requires a Python interpretter to process the bytecode. There really isn't a way to store all that in a C++ function pointer.
What you might be able to do is use the C++11 std::function
. This can be used like a function pointer, and can take any callable object (anything definiting operator()
). The idea would be that your class stores a std::function
instead of a function pointer.
#include <functional> // for std::function
class Foo {
private:
std::function<int(int,int)> stored_function;
public:
void setFooFunction(std::function<int(int,int)> f) {
stored_function = f;
}
void doSomething() {
// call it like this
int result = stored_function(1,2);
}
};
You then pass setFooFunction
a C++ class that stores a PyObject* (of the Python function), and defines operator()
to do the call to Python.
If you don't want to write the C++ class yourself, the boost::python::object
class (http://www.boost.org/doc/libs/1_58_0/libs/python/doc/v2/object.html#object_operators-spec) has the features you need. You can easily get a PyObject* from Cython
from cpython.ref cimport PyObject
cdef PyObject* pyob_ptr = <PyObject*>some_function
and converting that to the boost c++ class is reasonable simple too (http://www.boost.org/doc/libs/1_58_0/libs/python/doc/tutorial/doc/html/python/object.html#python.creating_python_object)
boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj_ptr)));
Since o
is callable, you should be able to use it directly in the std::function
Foo foo; // a foo object
foo.setFooFunction(o); // pass it the boost::python::object
(Obviously there's a lot of detail missing here, but hopefully the broad approach will be useful!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With