0

I have a C++ function ExecuteFunction that takes as input another function f.

I would like to expose ExecuteFunction in Python with Boost.Python, and call it from Python with either Python functions or other C++ functions as arguments. I've found plenty of information on how to pass Python functions to ExecuteFunction [1][2][3], but can't figure out how to specify a plain C++ function as argument.

Here is what I'm currently doing:

#include <boost/python.hpp>

typedef std::function<int(int)> Function;

int ExecuteFunction(int x, Function f) {
  return f(x);
};

int Half(int x) {
  return x / 2;
};

struct Square {
  int operator()(int x) const {
    return x * x;
  };
};

BOOST_PYTHON_MODULE(Test) {
  boost::python::def("ExecuteFunction", ExecuteFunction);
  boost::python::def("Half", Half);
  boost::python::class_<Square>("Square")
    .def("__call__", &Square::operator());
};

On the Python side I would like to do the following:

import Test

def Double(x):
    return x * 2

a = Test.ExecuteFunction(2, Test.Half)
b = Test.ExecuteFunction(2, Test.Square())
c = Test.ExecuteFunction(2, Double)

But the calls to Test.ExecuteFunction fail with the following tracebacks respectively:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Test.ExecuteFunction(int, Boost.Python.function)
did not match C++ signature:
    ExecuteFunction(int, std::function<int (int)>)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
    Test.ExecuteFunction(int, Square)
did not match C++ signature:
    ExecuteFunction(int, std::function<int (int)>)
Boost.Python.ArgumentError: Python argument types in
    Test.ExecuteFunction(int, function)
did not match C++ signature:
    ExecuteFunction(int, std::function<int (int)>)

I'm not really interested in calling Half and Square on the Python side (although being able to do so would be nice). I would be satisfied with being able to specify the right argument to ExecuteFunction. How could I do this?

1 Answer 1

1

As far as I can tell exposed C++ functions are always converted to a Python equivalent when constructed/invoked in Python. Hence ExecuteFunction should take as input a boost::python::object, not a std::function, even if you only intend to pass C++ functions as argument. You can then call the function and retrieve its return value with boost::python::call.

The following wound up working:

#include <boost/python.hpp>

int ExecuteFunctionWrapper(int x, const boost::python::object& f) {
  return boost::python::call<int>(f.ptr(), x);
};

int Half(int x) {
  return x / 2;
};

struct Square {
  int operator()(int x) const {
    return x * x;
  };
};

BOOST_PYTHON_MODULE(Test) {
  boost::python::def("ExecuteFunction", ExecuteFunctionWrapper);
  boost::python::def("Half", Half);
  boost::python::class_<Square>("Square")
    .def("__call__", &Square::operator());
};
import Test

def Double(x):
    return x * 2

a = Test.ExecuteFunction(4, Test.Half)
b = Test.ExecuteFunction(4, Test.Square())
c = Test.ExecuteFunction(4, Double)
print(a, b, c)
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.