[C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code?

Holger Brandsmeier brandsmeier at gmx.de
Sat Oct 27 19:14:44 CEST 2012


Paul,

Oh, all of these approaches can be made to work, just not as direct as
".def( "register_tau4ehS", register_tau4ehS)". If you at least relax
your callback mechanism a little and allow that for a callback you
both store a function pointer and an arbitrary object for the context,
void* or better a smart pointer, then you can hide instances of
classes in that mechanism nicely. And still you can use a raw function
pointer as before.

-Holger

On Sat, Oct 27, 2012 at 6:37 PM, Paul O.  Seidon <p.oseidon at datec.at> wrote:
> I see, thank you Holger,
>
> I did something similar at first, I did the registering and calling in a
> Python wrapper. But creating an EventEmitter is rather expensive compared to
> the creation of a Variable impl'ed in cpp. So I wanted to move that code to
> cpp too.
>
> BTW, SWIG does it this way too. There you have to add code wich is called
> before/after the call into cpp.
>
> Tanks
> Paul
>
>
> Holger Brandsmeier wrote:
>
>> Paul,
>>
>> if I see this correctly, then you are trying to register a function to
>> python in
>>       .def( "register_tau4ehS", register_tau4ehS)
>> which is expecting a pointer to a function to python. You can not do
>> that. Python can not pass function pointers as arguments, and so can't
>> boost::python.
>>
>> When I want to use the callback design pattern with python, I do the
>> following. A callback is for me an _object_ with has a certain member
>> function, say `call`, and that expects arguments as you want them, in
>> your case EventEmitterSync3<TYPE>&. When I register the class I pass a
>> shared_ptr to that object. Later I can call that object.
>>
>> In python I make a wrapper for that class, and in python I derive from
>> that class. Then in python I instantiate those derived classes and can
>> pass them to the register method. (Usually I like to create a class in
>> python that in the constructor takes a lambda function.)
>>
>> -Holger
>>
>> On Sat, Oct 27, 2012 at 4:12 PM, Paul O.  Seidon <p.oseidon at datec.at>
>> wrote:
>>> I want to register Python-callables with my VariableFloat-class (which is
>>> a subclass of a template-class Variable<double>) and call them if the
>>> variable's value changes.
>>>
>>> For this I added an instance of class EventEmitter, which should hold
>>> references to those callbacks. So, VariableFloat delegates to
>>> EventEmitter, when it comes to deal with callbacks (reg'ing and calling).
>>>
>>> template <class TYPE>
>>> class EventEmitterSync3
>>> {
>>> public:
>>>
>>> <snip/>
>>>
>>>     void                        operator()() // Call the handler
>>>                                 {
>>>                                     if (_p_tau4eh)
>>>                                         (*_p_tau4eh)( *this);
>>>                                 };
>>>
>>>     void                        register_tau4ehS( void (*callable)(
>>> EventEmitterSync3<TYPE>& )) // Register the handler
>>>                                 {   _p_tau4eh = callable;
>>>                                 };
>>> <snip/>
>>>
>>> private:
>>>     void                        (*_p_tau4eh)( EventEmitterSync3<TYPE>& )
>>>     =
>>> NULL; // The handler
>>> };
>>>
>>>
>>> The class VariableFloat (actually its base class _Variable<TYPE>) holds a
>>> member of type EventEmitterSync<TYPE> like so:
>>>
>>> private:
>>>     EventEmitterSync3<TYPE>     _tau4ee_on_change;
>>>
>>> and the wrapper definitions are
>>>
>>> void    (VariableFloat::*register_tau4ehS)( void (*)(
>>> EventEmitterSync3<double>& )) = &VariableFloat::register_tau4ehS;
>>>
>>> and
>>>
>>>         .def( "register_tau4ehS", register_tau4ehS)
>>>
>>>
>>> Compiling yields errors coming from boost being rather cryptic to me. But
>>> the last few lines say:
>>>
>>>
> /media/truecrypt13/D.X/Projects/DDG/tau4/src/cpp/src/tau4misc/main.cpp:43:1:
>>> required from here
>>> /usr/include/boost/python/converter/registered.hpp:86:7: error: no
>>> matching function for call to ?register_shared_ptr1(void (*)
>>> (EventEmitterSync3<double>&))?
>>> /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate
>>> is: /usr/include/boost/python/converter/registered.hpp:77:3: note:
>>> template<class T> void
>>> boost::python::converter::detail::register_shared_ptr1(const volatile T*)
>>> /usr/include/boost/python/converter/registered.hpp:77:3: note:   template
>>> argument deduction/substitution failed:
>>> /usr/include/boost/python/converter/registered.hpp:86:7: note:   types
>>> ?const volatile T? and ?void(EventEmitterSync3<double>&)? have
>>> incompatible cv-qualifiers
>>>
>>> Seems I have to put "const volatile" somewhere?
>>>
>>> I found some dox, which could be relevant, here:
>>> http://www.boost.org/doc/libs/1_51_0/libs/python/doc/v2/callbacks.html
>>>
>>> But I am not sure how to apply that info to my problem. I tried to change
>>> all function pointers into objects, but that didn't work.
>>>
>>> Has anyone some sample code on storing pointers to Python functions and
>>> then calling them and is willing to share it?
>>>
>>> Paul
>>>
>>>
>>>
>>>
>>>
>>>
>>> _______________________________________________
>>> Cplusplus-sig mailing list
>>> Cplusplus-sig at python.org
>>> http://mail.python.org/mailman/listinfo/cplusplus-sig
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig


More information about the Cplusplus-sig mailing list