I have code that wishes to call a python function from C++. Based on suggestions from https://cppyy.readthedocs.io/en/latest/functions.html#callbacks I wrote this:
ns.cppyy.cppdef("""
#include "CPyCppyy/API.h"
using namespace ns3;
EventImpl* BoundFunctionEvent(void (*function)(void))
{
std::cout << "binding" << std::endl;
return MakeEvent(function);
}
""")
def _schedule(delay, callable, *args, **kwargs):
bound_callable = functools.partial(callable, *args, **kwargs)
ns.core.Simulator.Schedule(delay, ns.cppyy.gbl.BoundFunctionEvent(bound_callable))
def hello():
print('hello')
_schedule(ns.core.Seconds(1.0), hello)
ns.core.Simulator.Run()
Now, if I run the above, I get this backtrace:
Traceback (most recent call last):
File "/source/ns-3-dev/build/./ns3.py", line 58, in <module>
main()
File "/source/ns-3-dev/build/./ns3.py", line 55, in main
args.func(args)
File "/source/ns-3-dev/build/./ns3.py", line 42, in run
ns.core.Simulator.Run()
TypeError: static void ns3::Simulator::Run() =>
TypeError: callable was deleted
Which, really, makes perfect sense: yes, the python callable went out of scope when the C++ code tries to call it later.
The question is: how can I convince the binding/C++ code to take ownership of the callable so it still lives when it is called by C++ ?
I did not find an answer to the exact question I asked but I did find a solution to my problem so, here it is in the hope this helps whoever has a similar question.
In my case, it just so happened that the C++ code I needed to hand over my callable to defined a C++ abstract base class that wrapped the functor so, all I had to do was to wrap my python callable in a python subclass of the event abstract base class (which, really, I had no idea was actually possible with cppyy: amazing piece of technology !). This looks like the following:
Notice above the
__python_owns__ = False
that does for this object what I was trying to do for my python callable in my initial question.