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

Paul O. Seidon p.oseidon at datec.at
Sat Oct 27 21:16:04 CEST 2012


Ah, yes, good idea. I would register an instance of a wrapper with a 
__call__ method, that would call my Python callback.

Thanks!
Paul


Holger Brandsmeier wrote:

> 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