I want to pass a callable object from Python to C++ and then call it from C++ with arguments for which I have registered base_
. Example:
namespace bpy = boost::python;
bpy::class_<X, X*, boost::noncopyable>("X", bpy::no_init);
bpy::def("f", +[](bpy::object fn) {
fn(new X());
});
Then from python:
from example import f
def fn(x):
print "x.g() =", x.g()
f(fn)
Throws:
TypeError: No to_python (by-value) converter found for C++ type: X
I have no issue with callable taking other types of arguments, e.g., int
, float
or some other types I have registered, but this one is failing and I don't understand why: why is a by-value conversion required when I'm passing a X*
and I've specified that the held type for X
is X*
.
Any suggestion on how to fix this?
Full example on Coliru: http://coliru.stacked-crooked.com/a/b3492d2e846d705c
According to Argument Handling in Calling Python Functions and Methods:
Arguments are converted to Python according to their type. By default, the arguments a1...aN are copied into new Python objects, but this behavior can be overridden by the use of ptr() and ref():
class X : boost::noncopyable { ... };
void apply(PyObject* callable, X& x) { // Invoke callable, passing a Python object which holds a reference to x
boost::python::call(callable, boost::ref(x)); }
It seems that even though the pointer type is specified the implementation takes the base non-pointer type. But in this case either boost::ref
or bpy::ptr
can be used to fix the problem anyway.
Change:
bpy::def("f", +[](bpy::object fn) {
fn(new X());
});
into:
bpy::def("f", +[](bpy::object fn) {
return fn(bpy::ptr(new X()));
});
And now it works:
$ python test.py
x.g() = 0