1

In general what is the recommended way to pass a Python function through Boost-Python for use later in C++ code (i.e. as a callback in a C++ object)?

More specifically, I have a C++ class FooCPP that I've successfully exposed to Python via Boost-Python; the user interacts with the Python class Foo that runs the C++ counterpart under the hood. Contrived example:

# Foo.py

from foo_base import FooBase

class Foo(FooBase):
    ...

def callback(val=42.):
    return val

foo = Foo()
foo.run(callback)

And the Boost Python bindings:

// foo_bindings.cpp

#include "foo.hpp"
#include <boost/python.hpp>

namespace bp =  boost::python;

FooPython::Run(const bp::object& py_callback)
    // TODO: Do something with the python callback to make it a C++ function!
    std::function<double(double)> cpp_callback;
    FooCPP::Run(cpp_callback);
)

BOOST_PYTHON_MODULE(foo_base){
    bp::class_<FooPython>("FooBase")
    .def("run", &FooPython::Run)
    ;
}

So how can I address the TODO comment in foo_bindings.cpp?

I've gone through a number of related SO questions -- e.g. pass python function to boost c and sending py function as boost function arg -- and I'm familiar with the Boost-Python docs, but have not found a good solution/explanation. Thanks in advance!

Notes: C++11, boost v1.58.0, ubuntu 16.04

Update

I may have just found a solution, where I can implement a functor in foo_bindings.cpp, e.g.,

struct PythonCallback {
public:
    PythonCallback(bp::object cb_func) : cb_func_(cb_func) {}
    double operator() (const double& val) {
        // Call the callback function in python
        return cb_func_(val);
    }
private:
    bp::object cb_func_;
};

But then what should the FooCPP::Run signature be? I.e. what type is defined for the cpp_callback passed in?

And does the BOOST_PYTHON_MODULE code need to change for this callback functor?

2
  • Do you just need to do this for a single function type (eg: double(double)) or something more generic? Commented Jun 6, 2018 at 16:55
  • @SeanMcAllister if there is a solution for a more generic callback function that takes in other args -- e.g. callback(x, y=42., z=True) -- that'd be great to see. Commented Jun 6, 2018 at 17:04

1 Answer 1

1

Implement a functor in foo_bindings.cpp, where the callback is invoked with call:

#include <boost/python.hpp>
#include <boost/python/call.hpp>

struct PythonCallback : {
public:
    PythonCallback(PyObject* func) : cb_(func) {}
    double operator() (const double& value) {
        // Call the callback function in python
        return boost::python::call<double>(cb_, value);
    }
private:
    PyObject* cb_;
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.