avoid C++ -> Python -> C++ overheads when passing around function objects
diff --git a/example/example5.cpp b/example/example5.cpp
index 0e1d2cd..3c144f2 100644
--- a/example/example5.cpp
+++ b/example/example5.cpp
@@ -65,6 +65,29 @@
py::arg("number"));
}
+int dummy_function(int i) { return i + 1; }
+int dummy_function2(int i, int j) { return i + j; }
+std::function<int(int)> roundtrip(std::function<int(int)> f) {
+ std::cout << "roundtrip.." << std::endl;
+ return f;
+}
+
+void test_dummy_function(const std::function<int(int)> &f) {
+ using fn_type = int (*)(int);
+ auto result = f.target<fn_type>();
+ if (!result) {
+ std::cout << "could not convert to a function pointer." << std::endl;
+ auto r = f(1);
+ std::cout << "eval(1) = " << r << std::endl;
+ } else if (*result == dummy_function) {
+ std::cout << "argument matches dummy_function" << std::endl;
+ auto r = (*result)(1);
+ std::cout << "eval(1) = " << r << std::endl;
+ } else {
+ std::cout << "argument does NOT match dummy_function. This should never happen!" << std::endl;
+ }
+}
+
void init_ex5(py::module &m) {
py::class_<Pet> pet_class(m, "Pet");
pet_class
@@ -113,4 +136,10 @@
/* p should be cleaned up when the returned function is garbage collected */
};
});
+
+ /* Test if passing a function pointer from C++ -> Python -> C++ yields the original pointer */
+ m.def("dummy_function", &dummy_function);
+ m.def("dummy_function2", &dummy_function2);
+ m.def("roundtrip", &roundtrip);
+ m.def("test_dummy_function", &test_dummy_function);
}
diff --git a/example/example5.py b/example/example5.py
index 1361c75..2526042 100755
--- a/example/example5.py
+++ b/example/example5.py
@@ -54,3 +54,30 @@
print("func(number=43) = %i" % f(number=43))
test_cleanup()
+
+from example import dummy_function
+from example import dummy_function2
+from example import test_dummy_function
+from example import roundtrip
+
+test_dummy_function(dummy_function)
+test_dummy_function(roundtrip(dummy_function))
+test_dummy_function(lambda x: x + 2)
+
+try:
+ test_dummy_function(dummy_function2)
+ print("Problem!")
+except Exception as e:
+ if 'Incompatible function arguments' in str(e):
+ print("All OK!")
+ else:
+ print("Problem!")
+
+try:
+ test_dummy_function(lambda x, y: x + y)
+ print("Problem!")
+except Exception as e:
+ if 'missing 1 required positional argument' in str(e):
+ print("All OK!")
+ else:
+ print("Problem!")
diff --git a/example/example5.ref b/example/example5.ref
index f32ba3a..c2e8eef 100644
--- a/example/example5.ref
+++ b/example/example5.ref
@@ -1,20 +1,13 @@
Rabbit is a parrot
-Polly is a parrot
-Molly is a dog
-Woof!
-func(43) = 44
-Payload constructor
-Payload copy constructor
-Payload move constructor
-Payload destructor
-Payload destructor
-Payload destructor
Rabbit is a parrot
Polly is a parrot
+Polly is a parrot
Molly is a dog
+Molly is a dog
+Woof!
The following error is expected: Incompatible function arguments. The following argument types are supported:
1. (example.Dog) -> NoneType
- Invoked with: <Pet object at 0>
+ Invoked with: <example.Pet object at 0>
Callback function 1 called!
False
Callback function 2 called : Hello, x, True, 5
@@ -24,4 +17,22 @@
Callback function 3 called : Partial object with one argument
False
func(43) = 44
+func(43) = 44
func(number=43) = 44
+Payload constructor
+Payload copy constructor
+Payload move constructor
+Payload destructor
+Payload destructor
+Payload destructor
+argument matches dummy_function
+eval(1) = 2
+roundtrip..
+argument matches dummy_function
+eval(1) = 2
+could not convert to a function pointer.
+eval(1) = 3
+could not convert to a function pointer.
+All OK!
+could not convert to a function pointer.
+All OK!