From grabber at gmail.com Mon Oct 1 04:26:23 2012 From: grabber at gmail.com (Luiz Vitor Martinez Cardoso) Date: Sun, 30 Sep 2012 23:26:23 -0300 Subject: [C++-sig] No Python class registered and a simple Qt type. Why? Message-ID: Dear, I'm trying to integrate a simple Qt/C++ and Python... but I'm getting "*TypeError: No Python class registered for C++ class QString*" error message and I can't realize why. I already have read dozen of posts on mailing lists and Google search results... but I can't figure out the solution in my brain. Could someone help me? I'm attaching all the relevante code I use. Read it from last to the beginning =] *Boost.Python converters* * * > #ifndef QTTOPYOBJECTS_H > #define QTTOPYOBJECTS_H > #include "faceobject.h" > #include > using namespace boost::python; > // C = QList > template > struct QList_to_python_list > { > typedef typename C::value_type T; > typedef typename C::const_iterator iter; > static PyObject* convert(C const &list) > { > // the python list > boost::python::list pyList; > foreach (const T& item, list) { > pyList.append(item); > } > return incref(pyList.ptr()); > } > }; > // C = QList > template > struct QList_ptr_to_python_list > { > typedef typename C::value_type T; > typedef typename C::const_iterator iter; > static PyObject* convert(C const &list) > { > // the python list > boost::python::list pyList; > // we need to wrap the pointers into PyObjects > typename boost::python::reference_existing_object::apply::type > converter; > for (iter i = list.begin(); i != list.end(); ++i) { > PyObject *obj = converter(*i); > object real_obj = object(handle<>(obj)); > // append the PyObject > pyList.append(real_obj); > } > return incref(pyList.ptr()); > } > }; > template > struct QList_ptr_from_python_list > { > typedef typename C::value_type T; > QList_ptr_from_python_list() > { > converter::registry::push_back( &convertible, &construct, type_id() > ); > } > static void* convertible(PyObject *obj_ptr) > { > //is this a tuple type? > if (PyTuple_Check(obj_ptr)) { > //check the tuple elements... - convert to a boost::tuple object > boost::python::tuple t( handle<>(borrowed(obj_ptr)) ); > //how many elements are there? > int n = PyTuple_Size(obj_ptr); > //can they all be converted to type 'T'? > for (int i=0; i if (!boost::python::extract(t[i]).check()) > return 0; > } > //the tuple is ok! > return obj_ptr; > } > //is this a list type? > else if (PyList_Check(obj_ptr)) { > //check that all of the list elements can be converted to the right > type > boost::python::list l( handle<>(borrowed(obj_ptr)) ); > //how many elements are there? > int n = PyList_Size(obj_ptr); > //can all of the elements be converted to type 'T'? > for (int i=0; i if (!boost::python::extract(l[i]).check()) > return 0; > } > //the list is ok! > return obj_ptr; > } > //could not recognise the type... > return 0; > } > static void construct(PyObject *obj_ptr, > converter::rvalue_from_python_stage1_data *data) > { > if (PyTuple_Check(obj_ptr)) { > //convert the PyObject to a boost::python::object > boost::python::tuple t( handle<>(borrowed(obj_ptr)) ); > //locate the storage space for the result > void* storage = > ((converter::rvalue_from_python_storage*)data)->storage.bytes; > //create the T container > new (storage) C(); > C *container = static_cast(storage); > //add all of the elements from the tuple - get the number of > elements in the tuple > int n = PyTuple_Size(obj_ptr); > for (int i=0; i container->append( extract(t[i])() ); > data->convertible = storage; > } > else if (PyList_Check(obj_ptr)) { > //convert the PyObject to a boost::python::object > boost::python::list l( handle<>(borrowed(obj_ptr)) ); > //locate the storage space for the result > void* storage = > ((converter::rvalue_from_python_storage*)data)->storage.bytes; > //create the T container > new (storage) C(); > C *container = static_cast(storage); > //add all of the elements from the tuple - get the number of > elements in the tuple > int n = PyList_Size(obj_ptr); > for (int i=0; i container->append( extract(l[i])() ); > data->convertible = storage; > } > } > }; > struct QString_to_python_str > { > // FIXME: handle this using boost::python::str > static PyObject* convert(QString const &str) > { > #if defined ( Py_UNICODE_WIDE ) > PyObject *obj = PyUnicode_FromUnicode( 0, str.length() ); > if (!obj) > throw_error_already_set(); > Py_UNICODE *pyu = PyUnicode_AS_UNICODE( obj ); > for (int i = 0; i < str.length(); ++i) > *pyu++ = (str.at(i)).unicode(); > return obj; > #else > return PyUnicode_FromWideChar( (const wchar_t*) str.unicode(), > str.length() ); > #endif > } > }; > struct QString_from_python_str > { > QString_from_python_str() > { > converter::registry::push_back( &convertible, &construct, > type_id() ); > } > static void* convertible(PyObject *obj_ptr) > { > if (PyUnicode_Check(obj_ptr)) > return obj_ptr; > if (PyString_Check(obj_ptr)) > return obj_ptr; > return 0; > } > static void construct(PyObject *obj_ptr, > converter::rvalue_from_python_stage1_data *data) > { > if (PyUnicode_Check(obj_ptr)) { > void *storage = ((converter::rvalue_from_python_storage *) > data)->storage.bytes; > PY_UNICODE_TYPE *ucode = PyUnicode_AS_UNICODE(obj_ptr); > int len = PyUnicode_GET_SIZE(obj_ptr); > #if defined(Py_UNICODE_WIDE) > QString* out = new(storage) QString; > for ( int i = 0; i < len; ++i ) > out->append( (uint)ucode[i] ); > #else > new(storage) QString( (const QChar *)ucode, len ); > #endif > data->convertible = storage; > } else if ( PyString_Check( obj_ptr ) ) { > const char *value = PyString_AsString(obj_ptr); > if(!value) > throw_error_already_set(); > void *storage = ((converter::rvalue_from_python_storage *) > data)->storage.bytes; > new(storage) QString(QByteArray(value, PyString_Size(obj_ptr))); > data->convertible = storage; > } > } > }; > template > struct QList_from_python_list > { > typedef typename C::value_type T; > QList_from_python_list() > { > converter::registry::push_back( &convertible, &construct, type_id() > ); > } > static void* convertible(PyObject *obj_ptr) > { > //is this a tuple type? > if (PyTuple_Check(obj_ptr)) { > //check the tuple elements... - convert to a boost::tuple object > boost::python::tuple t( handle<>(borrowed(obj_ptr)) ); > //how many elements are there? > int n = PyTuple_Size(obj_ptr); > //can they all be converted to type 'T'? > for (int i=0; i if (!boost::python::extract(t[i]).check()) > return 0; > } > //the tuple is ok! > return obj_ptr; > } > //is this a list type? > else if (PyList_Check(obj_ptr)) { > //check that all of the list elements can be converted to the right > type > boost::python::list l( handle<>(borrowed(obj_ptr)) ); > //how many elements are there? > int n = PyList_Size(obj_ptr); > //can all of the elements be converted to type 'T'? > for (int i=0; i if (!boost::python::extract(l[i]).check()) > return 0; > } > //the list is ok! > return obj_ptr; > } > //could not recognise the type... > return 0; > } > static void construct(PyObject *obj_ptr, > converter::rvalue_from_python_stage1_data *data) > { > if (PyTuple_Check(obj_ptr)) { > //convert the PyObject to a boost::python::object > boost::python::tuple t( handle<>(borrowed(obj_ptr)) ); > //locate the storage space for the result > void* storage = > ((converter::rvalue_from_python_storage*)data)->storage.bytes; > //create the T container > new (storage) C(); > C *container = static_cast(storage); > //add all of the elements from the tuple - get the number of > elements in the tuple > int n = PyTuple_Size(obj_ptr); > for (int i=0; i container->append( extract(t[i])() ); > data->convertible = storage; > } > else if (PyList_Check(obj_ptr)) { > //convert the PyObject to a boost::python::object > boost::python::list l( handle<>(borrowed(obj_ptr)) ); > //locate the storage space for the result > void* storage = > ((converter::rvalue_from_python_storage*)data)->storage.bytes; > //create the T container > new (storage) C(); > C *container = static_cast(storage); > //add all of the elements from the tuple - get the number of > elements in the tuple > int n = PyList_Size(obj_ptr); > for (int i=0; i container->append( extract(l[i])() ); > data->convertible = storage; > } > } > }; > > void export_QList() > { > to_python_converter< QList, QList_ptr_to_python_list< > QList > >(); > QList_ptr_from_python_list< QList >(); > } void export_QString() > { > to_python_converter< QString, QString_to_python_str >(); > QString_from_python_str(); > } #endif // QTTOPYOBJECTS_H *C++* > class QListTest > { > public: > QList constantStringList() > { > QList list; > list.append(QString("test 1")); > list.append(QString("test 2")); > list.append(QString("test 3")); > return list; > } > const QList& stringList() const > { > return m_list; > } > void setStringList(QList list) > { > m_list = list; > } > private: > QList m_list; > }; > > BOOST_PYTHON_MODULE(libfaceparser) > { > export_QString(); > export_QList(); > class_("QListTest") > .def("constantStringList", &QListTest::constantStringList) > .def("stringList", &QListTest::stringList, > return_value_policy()) > .def("setStringList", &QListTest::setStringList) > ; > } *Python* import libfaceparser > > fp = libfaceparser.QListTest() > print fp.constantStringList() *Python Console* > lmvc at debian:~/Projects/adbox_server/adbox_parser/software/output/debug$ > python faceparser.py > Traceback (most recent call last): > File "faceparser.py", line 7, in > print fp.constantStringList() > TypeError: No Python class registered for C++ class QString Best regards, Luiz Vitor. -- Regards, Luiz Vitor Martinez Cardoso Celular: (11) 7351-7097 | Skype: grabberbr engineer student at maua.br intern marketing engineer at geindustrial.com.br entrepreneur at adboxnetwork.com "If you wanna be successful, you need total dedication, go for your last limit, give your best and love your love infinitely!" "The only limits are the ones you place upon yourself" -------------- next part -------------- An HTML attachment was scrubbed... URL: From grabber at gmail.com Tue Oct 2 18:29:55 2012 From: grabber at gmail.com (Luiz Vitor Martinez Cardoso) Date: Tue, 2 Oct 2012 13:29:55 -0300 Subject: [C++-sig] How to hangle a NULL pointer? Message-ID: Dear, I've a simple C++ class containing the following members: quint32 mergeCount; quint64 timestamp; quint32 id; quint32 score; quint32 lastScore; quint32 uptime; qint32 * gender; float * age; float * ageDeviationDen; quint32 * happy; quint32 * sad; quint32 * surprised; quint32 * angry; All the members are initialized to 0 or NULL if it's a pointer. The problem is that I'm getting a "Segmentation Fault" message when I try to access the pointers members from Python. The code I'm using to map the attributes are: void export_FaceObject() > { > class_("FaceObject", init<>()) > .add_property("mergecount", &FaceObject::getMergeCount) > .add_property("id", &FaceObject::getId) > .add_property("timestamp", &FaceObject::getTimestamp) > .add_property("score", &FaceObject::getScore) > .add_property("lastscore", &FaceObject::getLastScore) > .add_property("uptime", &FaceObject::getUptime) > .add_property("gender", &FaceObject::getGender) > .add_property("age", &FaceObject::getAge) > .add_property("agedeviation", &FaceObject::getAgeDeviation) > .add_property("happy", &FaceObject::getHappy) > .add_property("sad", &FaceObject::getSad) > .add_property("surprised", &FaceObject::getSurprised) > .add_property("angry", &FaceObject::getAngry) > ; > } What can I do? I know that I need to use a CallPolicy but I already have tried several combinations without any success. Best regards, Luiz Vitor. -- Regards, Luiz Vitor Martinez Cardoso Celular: (11) 7351-7097 | Skype: grabberbr engineer student at maua.br intern marketing engineer at geindustrial.com.br entrepreneur at adboxnetwork.com "If you wanna be successful, you need total dedication, go for your last limit, give your best and love your love infinitely!" "The only limits are the ones you place upon yourself" -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan at seefeld.name Tue Oct 2 18:35:48 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Tue, 02 Oct 2012 12:35:48 -0400 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: References: Message-ID: <506B17E4.3010805@seefeld.name> On 10/02/2012 12:29 PM, Luiz Vitor Martinez Cardoso wrote: > > All the members are initialized to 0 or NULL if it's a pointer. > > The problem is that I'm getting a "Segmentation Fault" message when I > try to access the pointers members from Python. Can you elaborate on what you want to happen in that case ? Python has no notion of pointers, so the pointers would need to be dereferenced. If that isn't what you want, you need to add some logic to return something else if the members are not initialized yet. Stefan -- ...ich hab' noch einen Koffer in Berlin... From grabber at gmail.com Tue Oct 2 18:44:00 2012 From: grabber at gmail.com (Luiz Vitor Martinez Cardoso) Date: Tue, 2 Oct 2012 13:44:00 -0300 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: <506B17E4.3010805@seefeld.name> References: <506B17E4.3010805@seefeld.name> Message-ID: Stefan, Thank you! To clarify my explanation... the pointer declarations are members from a class called FaceObject. qint32 * gender; float * age; float * ageDeviationDen; quint32 * happy; quint32 * sad; quint32 * surprised; quint32 * angry; Depending on the software flow these pointers may or may not be initialized. The problem occurs when the pointers are not initialized (poiting to NULL) and I try to read their value inside Python. # faceobject_poc.py t = faceparser.FaceObject() t.mergeCount <= It's okay! t.gender <= I got an Seg. Fault... because qint32 * gender = NULL I of course could try a qint32 * gender = new quint32()... but do you know any way to handle the non-intialized members? Thank you! On Tue, Oct 2, 2012 at 1:35 PM, Stefan Seefeld wrote: > On 10/02/2012 12:29 PM, Luiz Vitor Martinez Cardoso wrote: > > > > All the members are initialized to 0 or NULL if it's a pointer. > > > > The problem is that I'm getting a "Segmentation Fault" message when I > > try to access the pointers members from Python. > > Can you elaborate on what you want to happen in that case ? Python has > no notion of pointers, so the pointers would need to be dereferenced. If > that isn't what you want, you need to add some logic to return something > else if the members are not initialized yet. > > Stefan > > > -- > > ...ich hab' noch einen Koffer in Berlin... > > _______________________________________________ > Cplusplus-sig mailing list > Cplusplus-sig at python.org > http://mail.python.org/mailman/listinfo/cplusplus-sig > -- Regards, Luiz Vitor Martinez Cardoso Celular: (11) 7351-7097 | Skype: grabberbr engineer student at maua.br intern marketing engineer at geindustrial.com.br entrepreneur at adboxnetwork.com "If you wanna be successful, you need total dedication, go for your last limit, give your best and love your love infinitely!" "The only limits are the ones you place upon yourself" -------------- next part -------------- An HTML attachment was scrubbed... URL: From grabber at gmail.com Tue Oct 2 18:51:29 2012 From: grabber at gmail.com (Luiz Vitor Martinez Cardoso) Date: Tue, 2 Oct 2012 13:51:29 -0300 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: References: <506B17E4.3010805@seefeld.name> Message-ID: Stefan, I would like to do on the Python side: t = faceparser.FaceObject() if (t.gender = None): print 'gender is not defined' else: print gender Best regards, Luiz Vitor. On Tue, Oct 2, 2012 at 1:44 PM, Luiz Vitor Martinez Cardoso < grabber at gmail.com> wrote: > Stefan, > > Thank you! > > To clarify my explanation... the pointer declarations are members from a > class called FaceObject. > > qint32 * gender; > float * age; > float * ageDeviationDen; > quint32 * happy; > quint32 * sad; > quint32 * surprised; > quint32 * angry; > > Depending on the software flow these pointers may or may not be > initialized. > > The problem occurs when the pointers are not initialized (poiting to NULL) > and I try to read their value inside Python. > > # faceobject_poc.py > > t = faceparser.FaceObject() > t.mergeCount <= It's okay! > t.gender <= I got an Seg. Fault... because qint32 * gender = NULL > > > I of course could try a qint32 * gender = new quint32()... but do you know > any way to handle the non-intialized members? > > Thank you! > > > On Tue, Oct 2, 2012 at 1:35 PM, Stefan Seefeld wrote: > >> On 10/02/2012 12:29 PM, Luiz Vitor Martinez Cardoso wrote: >> > >> > All the members are initialized to 0 or NULL if it's a pointer. >> > >> > The problem is that I'm getting a "Segmentation Fault" message when I >> > try to access the pointers members from Python. >> >> Can you elaborate on what you want to happen in that case ? Python has >> no notion of pointers, so the pointers would need to be dereferenced. If >> that isn't what you want, you need to add some logic to return something >> else if the members are not initialized yet. >> >> Stefan >> >> >> -- >> >> ...ich hab' noch einen Koffer in Berlin... >> >> _______________________________________________ >> Cplusplus-sig mailing list >> Cplusplus-sig at python.org >> http://mail.python.org/mailman/listinfo/cplusplus-sig >> > > > > -- > Regards, > > Luiz Vitor Martinez Cardoso > Celular: (11) 7351-7097 | Skype: grabberbr > engineer student at maua.br > intern marketing engineer at geindustrial.com.br > entrepreneur at adboxnetwork.com > > "If you wanna be successful, you need total dedication, go for your last > limit, give your best and love your love infinitely!" > > "The only limits are the ones you place upon yourself" > > -- Regards, Luiz Vitor Martinez Cardoso Celular: (11) 7351-7097 | Skype: grabberbr engineer student at maua.br intern marketing engineer at geindustrial.com.br entrepreneur at adboxnetwork.com "If you wanna be successful, you need total dedication, go for your last limit, give your best and love your love infinitely!" "The only limits are the ones you place upon yourself" -------------- next part -------------- An HTML attachment was scrubbed... URL: From stefan at seefeld.name Tue Oct 2 18:58:49 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Tue, 02 Oct 2012 12:58:49 -0400 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: References: <506B17E4.3010805@seefeld.name> Message-ID: <506B1D49.7000801@seefeld.name> I would write little wrapper functions that check the pointer, and if it's NULL, return None instead of the dereferenced value. To illustrate: object get_age(FaceObject &f) { return f.getAge() ? object(*f.getAge()) : object();} ... class_(...).add_property("age", get_age); Thus, if the pointer is initialized, the value pointed to will be returned, and if not, None. -- ...ich hab' noch einen Koffer in Berlin... From vanv0059 at umn.edu Tue Oct 2 19:05:32 2012 From: vanv0059 at umn.edu (Jeffrey Van Voorst) Date: Tue, 02 Oct 2012 12:05:32 -0500 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: References: Message-ID: <506B1EDC.5020103@umn.edu> You might want to use wrapper functions in C++ boost::python::object gender_getter(const FaceObject& obj) { if(obj.gender == NULL) return Py_None; else return obj.gender; } Note: its been a bit since I used Boost.Python heavily. The syntax could be incorrect, but I hope this gives you a general idea. --Jeff Van Voorst From grabber at gmail.com Tue Oct 2 21:28:22 2012 From: grabber at gmail.com (Luiz Vitor Martinez Cardoso) Date: Tue, 2 Oct 2012 16:28:22 -0300 Subject: [C++-sig] How to hangle a NULL pointer? In-Reply-To: <506B1EDC.5020103@umn.edu> References: <506B1EDC.5020103@umn.edu> Message-ID: Stefan/Jeffrey, Thank you, it's now working perfectly... but I have another issue. I wrote: object get_py_gender(const FaceObject &fobj) > { > return fobj.gender ? object(*fobj.gender) : object(); > } > object get_py_age(const FaceObject &fobj) > { > return fobj.age ? object(*fobj.age) : object(); > } > object get_py_agedeviation(const FaceObject &fobj) > { > return fobj.ageDeviationDen ? object(*fobj.ageDeviationDen) : object(); > } > object get_py_happy(const FaceObject &fobj) > { > return fobj.happy ? object(*fobj.happy) : object(); > } > object get_py_sad(const FaceObject &fobj) > { > return fobj.sad ? object(*fobj.sad) : object(); > } > object get_py_surprised(const FaceObject &fobj) > { > return fobj.surprised ? object(*fobj.surprised) : object(); > } > object get_py_angry(const FaceObject &fobj) > { > return fobj.angry ? object(*fobj.angry) : object(); > } Well... the functions are doing the same thing and don't like so much the idea of repeating code unnecessarily, so I'm trying to write a template to handle it. template > object get_py_wrapper(T obj) > { > return obj ? object(*obj) : object(); > } My problem is how to call the template function. The next code shows the getAge function declaration. inline quint8 getAge() > { > return (quint8) qRound(*age / *ageDeviationDen); > } The class_ declaration (to bridge between languages) is: void export_FaceObject() > { > class_("FaceObject", init<>()) > . > . > . > .add_property("age", get_py_age) // <= It's working! > .add_property("age", get_py_wrapper(&FaceObject::getAge)) > . > . > . > ; > } And finally the error I'm getting is: In file included from faceparser.cpp:10:0: > ../../include/qttopyobjects.h: In function 'void export_FaceObject()': > ../../include/qttopyobjects.h:369:71: error: no matching function for call > to 'get_py_wrapper(quint8 (FaceObject::*)())' > ../../include/qttopyobjects.h:369:71: note: candidate is: > ../../include/qttopyobjects.h:353:8: note: template > boost::python::api::object get_py_wrapper(T) > ../../include/qttopyobjects.h:353:8: note: template argument > deduction/substitution failed: > ../../include/qttopyobjects.h:369:71: note: cannot convert > '&FaceObject::getAge' (type 'quint8 (FaceObject::*)() {aka unsigned char > (FaceObject::*)()}') to type 'unsigned char' I'm sure that I need to use &FaceObject::getAge and quint8... but I can't figure out what is going on. I already tried to do: .add_property("age", get_py_wrapper(reinterpret_cast(&FaceObject::getAge))) I appreciate your support very much! Best regards, Luiz Vitor On Tue, Oct 2, 2012 at 2:05 PM, Jeffrey Van Voorst wrote: > You might want to use wrapper functions in C++ > > boost::python::object > gender_getter(const FaceObject& obj) > { > if(obj.gender == NULL) return Py_None; > else return obj.gender; > } > > Note: its been a bit since I used Boost.Python heavily. The syntax could > be incorrect, but I hope this gives you a general idea. > > --Jeff Van Voorst > > ______________________________**_________________ > Cplusplus-sig mailing list > Cplusplus-sig at python.org > http://mail.python.org/**mailman/listinfo/cplusplus-sig > -- Regards, Luiz Vitor Martinez Cardoso Celular: (11) 7351-7097 | Skype: grabberbr engineer student at maua.br intern marketing engineer at geindustrial.com.br entrepreneur at adboxnetwork.com "If you wanna be successful, you need total dedication, go for your last limit, give your best and love your love infinitely!" "The only limits are the ones you place upon yourself" -------------- next part -------------- An HTML attachment was scrubbed... URL: From p.oseidon at datec.at Fri Oct 26 13:42:29 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Fri, 26 Oct 2012 13:42:29 +0200 Subject: [C++-sig] [boost.python] Can't import a wrapped template class Message-ID: Hi all, right now I'm doing my first stepps in wrapping C++ code by ude of Boost. So, there's a template class _Variable with ctor, dtor, an inspector TYPE value() const and a mutator void value( const TYPE& value). The boost wrapper looks like this: #include #include using namespace boost::python; #include "./src/varbls.h" #include using namespace std; typedef _Variable VariableDouble; BOOST_PYTHON_MODULE(_varbls) { class_("VariableDouble") .def( init<>()) .def( init()) ; } Nothing special so far. However, what I get upon import is this: ImportError: /usr/lib/python2.7/site-packages/tau4.DDG/tau4/tau4misc/varbls/cpp/boost/_varbls.so: undefined symbol: _ZN9_VariableIdEC1Ev The ctor is decl'ed as _Variable(); and ist's def'ed like so: template _Variable::_Variable() : _value( 0) { //ctor } To me, everything looks good, but obiously there's something wrong. What do I miss? Paul From stefan at seefeld.name Fri Oct 26 19:16:34 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Fri, 26 Oct 2012 13:16:34 -0400 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: Message-ID: <508AC572.4040002@seefeld.name> On 10/26/2012 07:42 AM, Paul O. Seidon wrote: > Hi all, > > right now I'm doing my first stepps in wrapping C++ code by ude of Boost. [...] Where is the definition of your _Variable template instances ? Your newly compiled Python module can't find them. The likely cause is that you forgot to link the module to the library containing the definition(s). Stefan -- ...ich hab' noch einen Koffer in Berlin... From p.oseidon at datec.at Fri Oct 26 19:50:24 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Fri, 26 Oct 2012 19:50:24 +0200 Subject: [C++-sig] [boost.python] Can't import a wrapped template class References: <508AC572.4040002@seefeld.name> Message-ID: Stefan Seefeld wrote: > On 10/26/2012 07:42 AM, Paul O. Seidon wrote: >> Hi all, >> >> right now I'm doing my first stepps in wrapping C++ code by ude of Boost. > > [...] > > Where is the definition of your _Variable template instances ? Your > newly compiled Python module can't find them. The likely cause is that > you forgot to link the module to the library containing the definition(s). > > Stefan > > Not sure what you mean: The ctor is decl'ed in varbls.h as _Variable(); and it's def'ed in varbls.cpp like so: template _Variable::_Variable() : _value( 0) { //ctor } I did a typedef in the wrapper and wrote BOOST_PYTHON_MODULE(_varbls) { class_("VariableDouble") .def( init<>()) .def( init()) ; } in the wrapper. Any instance of VariableDouble should then be def'ed in the importing Python module. Everything works fine if I do not use templates but plain C++ classes instead. Paul From stefan at seefeld.name Fri Oct 26 19:59:25 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Fri, 26 Oct 2012 13:59:25 -0400 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: <508AC572.4040002@seefeld.name> Message-ID: <508ACF7D.1000709@seefeld.name> On 10/26/2012 01:50 PM, Paul O. Seidon wrote: > The ctor is decl'ed in varbls.h as > > _Variable(); > > and it's def'ed in varbls.cpp like so: > > template > _Variable::_Variable() > : _value( 0) > { > //ctor > } That doesn't work. When the compiler compiles varbls.cpp, it doesn't know what types to instantiate the _Variable template for, so you need to either explicitly instantiate it for all the types you use in your module, or keep the definitions in the varbls.h header so the compiler can implicitly instantiate them when compiling the Python module. Stefan -- ...ich hab' noch einen Koffer in Berlin... From p.oseidon at datec.at Fri Oct 26 20:16:53 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Fri, 26 Oct 2012 20:16:53 +0200 Subject: [C++-sig] [boost.python] Can't import a wrapped template class References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: Stefan Seefeld wrote: > On 10/26/2012 01:50 PM, Paul O. Seidon wrote: >> The ctor is decl'ed in varbls.h as >> >> _Variable(); >> >> and it's def'ed in varbls.cpp like so: >> >> template >> _Variable::_Variable() >> : _value( 0) >> { >> //ctor >> } > > That doesn't work. When the compiler compiles varbls.cpp, it doesn't > know what types to instantiate the _Variable template for, so you need > to either explicitly instantiate it for all the types you use in your > module, or keep the definitions in the varbls.h header so the compiler > can implicitly instantiate them when compiling the Python module. > > Stefan > That didn't make any difference. And it would have surprised me, if it did: varbls.h contains the declaration, varbls.cpp contains the definition, the wrapper is in main.cpp. So if the compiler sees any need to include sometihng, it will and the linker will link the definition. But you certainly are right, the symbol is in the .so-file but the symbol isn't resolved by the linker. Hm, but where should I instantiate the class? I thought BOOST_PYTHON_MODULE(_varbls) { class_("VariableDouble") .def( init<>()) .def( init()) ; } would do that. Should I try dont_care = _Variable(); in main.cpp? Looks a bit strange, but would force the compiler to generate code for sure. Paul From p.oseidon at datec.at Fri Oct 26 20:24:33 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Fri, 26 Oct 2012 20:24:33 +0200 Subject: [C++-sig] [boost.python] Can't import a wrapped template class References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: Paul O. Seidon wrote: > Stefan Seefeld wrote: > >> On 10/26/2012 01:50 PM, Paul O. Seidon wrote: >>> The ctor is decl'ed in varbls.h as >>> >>> _Variable(); >>> >>> and it's def'ed in varbls.cpp like so: >>> >>> template >>> _Variable::_Variable() >>> : _value( 0) >>> { >>> //ctor >>> } >> >> That doesn't work. When the compiler compiles varbls.cpp, it doesn't >> know what types to instantiate the _Variable template for, so you need >> to either explicitly instantiate it for all the types you use in your >> module, or keep the definitions in the varbls.h header so the compiler >> can implicitly instantiate them when compiling the Python module. >> >> Stefan >> > > That didn't make any difference. And it would have surprised me, if it > did: varbls.h contains the declaration, varbls.cpp contains the > definition, the wrapper is in main.cpp. So if the compiler sees any need > to include sometihng, it will and the linker will link the definition. > > But you certainly are right, the symbol is in the .so-file but the symbol > isn't resolved by the linker. Hm, but where should I instantiate the > class? I thought > > BOOST_PYTHON_MODULE(_varbls) > { > > class_("VariableDouble") > .def( init<>()) > .def( init()) > ; > } > > would do that. Should I try > > dont_care = _Variable(); > > in main.cpp? Looks a bit strange, but would force the compiler to generate > code for sure. > > Paul That doesn't do it either. I can't help but post the compete code here to be sure I'm not misunderstood. The lib consists of varbls.cpp and varbls.h and the wrapper main.cpp. varbls.h ======== #ifndef VARBLS_H #define VARBLS_H template class _Variable { public: _Variable(); _Variable( const TYPE& v); virtual ~_Variable(); TYPE value() const; void value( const double& v); protected: private: TYPE _value; }; /* class VariableFloat : public _Variable { public: VariableFloat( const double& v) : _Variable( v) {}; virtual ~VariableFloat() {}; }; */ class VariableFloat { public: VariableFloat( const double& v=0) : _value( v) {}; virtual ~VariableFloat() {}; double value() const { return _value; }; void value( const double& v) { _value = v; }; private: double _value; }; #endif // VARBLS_H varbls.cpp ========== #include "varbls.h" template _Variable::_Variable() : _value( 0) { //ctor } template _Variable::_Variable( const TYPE& v) : _value( v) { //ctor } template _Variable::~_Variable() { //dtor } template TYPE _Variable::value() const { return _value; } template void _Variable::value( const double& v) { _value = v; } main.cpp ======== #include #include using namespace boost::python; #include "./src/varbls.h" #include using namespace std; typedef _Variable VariableDouble; /* void (VariableFloat::*value_1)( const double& ) = &VariableFloat::value; double (VariableFloat::*value_2)() const = &VariableFloat::value; */ BOOST_PYTHON_MODULE(_varbls) { class_("VariableDouble") .def( init<>()) .def( init()) ; /* class_("VariableFloat") .def( init<>()) .def( init()) .def( "value", value_1) .def( "value", value_2) ; */ } VariableDouble _DONT_CARE = VariableDouble(); Paul From stefan at seefeld.name Fri Oct 26 20:28:11 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Fri, 26 Oct 2012 14:28:11 -0400 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: <508AD63B.70103@seefeld.name> On 10/26/2012 02:16 PM, Paul O. Seidon wrote: > Stefan Seefeld wrote: > >> On 10/26/2012 01:50 PM, Paul O. Seidon wrote: >>> The ctor is decl'ed in varbls.h as >>> >>> _Variable(); >>> >>> and it's def'ed in varbls.cpp like so: >>> >>> template >>> _Variable::_Variable() >>> : _value( 0) >>> { >>> //ctor >>> } >> That doesn't work. When the compiler compiles varbls.cpp, it doesn't >> know what types to instantiate the _Variable template for, so you need >> to either explicitly instantiate it for all the types you use in your >> module, or keep the definitions in the varbls.h header so the compiler >> can implicitly instantiate them when compiling the Python module. >> >> Stefan >> > That didn't make any difference. And it would have surprised me, if it did: > varbls.h contains the declaration, varbls.cpp contains the definition, the > wrapper is in main.cpp. So if the compiler sees any need to include > sometihng, it will and the linker will link the definition. Sorry, let's back up a little. What are you referring to as "the definition" in the above ? Where is the "_Variable::_Variable()" constructor defined ? You didn't show me where it was. You only showed me the (still parametrized) definition in varbls.cpp. If the compiler sees the parametrized constructor definition, it doesn't know what types to instantiate it for, so it does nothing (other than validate the code to some degree). It's only when it instantiates the template for a particular type that it generates the missing symbol. But - according to the small chunks of code you have shown me - it only attempts that instantiation implicitly in your module's code. But at that point it doesn't see the constructor definition, so it can't instantiate that. Perhaps showing a little more of your code / setup would help. Stefan -- ...ich hab' noch einen Koffer in Berlin... From amohr at pixar.com Fri Oct 26 20:27:15 2012 From: amohr at pixar.com (Alex Mohr) Date: Fri, 26 Oct 2012 11:27:15 -0700 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: <508AD603.9040404@pixar.com> On 10/26/2012 11:16 AM, Paul O. Seidon wrote: > would do that. Should I try > > dont_care = _Variable(); > > in main.cpp? Looks a bit strange, but would force the compiler to generate > code for sure. You either need to inline the ctor in the header or do an explicit instantiation of _Variable somewhere. I suggest you read up on "explicit instantiation" and c++ templates in general. This problem isn't related to boost.python. Alex From stefan at seefeld.name Fri Oct 26 20:32:39 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Fri, 26 Oct 2012 14:32:39 -0400 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: <508AD747.3050904@seefeld.name> On 10/26/2012 02:24 PM, Paul O. Seidon wrote: > Paul O. Seidon wrote: > > That doesn't do it either. I can't help but post the compete code here to be > sure I'm not misunderstood. The lib consists of varbls.cpp and varbls.h and > the wrapper main.cpp. > varbls.cpp > ========== > > #include "varbls.h" > > > template > _Variable::_Variable() > : _value( 0) > { > //ctor > } [...] What symbols does your compiled varbls.o file export ? I bet none. And it can't. That's the problem I'm trying to explain. Stefan -- ...ich hab' noch einen Koffer in Berlin... From p.oseidon at datec.at Fri Oct 26 22:15:42 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Fri, 26 Oct 2012 22:15:42 +0200 Subject: [C++-sig] [boost.python] Can't import a wrapped template class References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> <508AD747.3050904@seefeld.name> Message-ID: Stefan Seefeld wrote: > On 10/26/2012 02:24 PM, Paul O. Seidon wrote: >> Paul O. Seidon wrote: >> >> That doesn't do it either. I can't help but post the compete code here to >> be sure I'm not misunderstood. The lib consists of varbls.cpp and >> varbls.h and the wrapper main.cpp. > >> varbls.cpp >> ========== >> >> #include "varbls.h" >> >> >> template >> _Variable::_Variable() >> : _value( 0) >> { >> //ctor >> } > > [...] > > What symbols does your compiled varbls.o file export ? I bet none. And > it can't. That's the problem I'm trying to explain. > > Stefan > As Alex said, this seems to be a C++ issue. Hope you'll help me nevertheless. There can't be that much that's missing. How do I do that export? This whole mess is caused by the use of a template class. You see, there's a class VariableFloat. It is not a template class and is not derived from a template class. And it works, I can use it from w/i my Python modules. Well, it's deactivated for now to prevent "side effects". Yes, I have to provide a TYPE to the tempate to enable the compiler to generate code. Isn't typedef _Variable VariableDouble; BOOST_PYTHON_MODULE(_varbls) { class_("VariableDouble") .def( init<>()) .def( init()) ; } doing that? Paul From stefan at seefeld.name Fri Oct 26 22:27:51 2012 From: stefan at seefeld.name (Stefan Seefeld) Date: Fri, 26 Oct 2012 16:27:51 -0400 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> <508AD747.3050904@seefeld.name> Message-ID: <508AF247.5080908@seefeld.name> On 10/26/2012 04:15 PM, Paul O. Seidon wrote: > Yes, I have to provide a TYPE to the tempate to enable the compiler to > generate code. Isn't > > typedef _Variable VariableDouble; > > BOOST_PYTHON_MODULE(_varbls) > { > > class_("VariableDouble") > .def( init<>()) > .def( init()) > ; > } > > doing that? The compiler can only generate code from templates it can see at the point where the instantiation happens. Since in the snippet above it doesn't see the _Variable constructor definition, it can't instantiate it. And at the point where it can see the constructor, it doesn't know that it needs to instantiate it for type 'double'. The entire issue disappears if you move your member function definitions (including the constructor) from varbls.cpp to varbls.h. Stefan -- ...ich hab' noch einen Koffer in Berlin... From amohr at pixar.com Fri Oct 26 22:41:23 2012 From: amohr at pixar.com (Alex Mohr) Date: Fri, 26 Oct 2012 13:41:23 -0700 Subject: [C++-sig] [boost.python] Can't import a wrapped template class In-Reply-To: <508AF247.5080908@seefeld.name> References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> <508AD747.3050904@seefeld.name> <508AF247.5080908@seefeld.name> Message-ID: <508AF573.3030803@pixar.com> On 10/26/2012 1:27 PM, Stefan Seefeld wrote: > The entire issue disappears if you move your member function definitions > (including the constructor) from varbls.cpp to varbls.h. Alternatively, explicitly instantiate in varbls.cpp. template class _Variable; Again, you might want to google "explicit template instantiation" or similar. Alex From p.oseidon at datec.at Sat Oct 27 09:05:07 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Sat, 27 Oct 2012 09:05:07 +0200 Subject: [C++-sig] [SOLVED] Re: [boost.python] Can't import a wrapped template class References: <508AC572.4040002@seefeld.name> <508ACF7D.1000709@seefeld.name> Message-ID: Paul O. Seidon wrote: > That didn't make any difference. And it would have surprised me, if it > did: varbls.h contains the declaration, varbls.cpp contains the > definition, the wrapper is in main.cpp. So if the compiler sees any need > to include sometihng, it will and the linker will link the definition. Well, it *makes* a difference if *all* of _Variable is moved from the cpp- to the h-file (as suggested by Stefan yesterday evening). Alex, I did the explicit template class instantiation (thanks for the hint) w/o success at first. Then I saw that I forgot to def the dtor in the h-file. Did it and *it worked*. I then even could remove the explicit template class instantiation. Thanks to you both keeping up with me doing the first steps in boost and the first steps in C++ after a pause of about 8 years. It's definitely worth using boost.python as it seems "lightning fast". Paul From p.oseidon at datec.at Sat Oct 27 16:12:02 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Sat, 27 Oct 2012 16:12:02 +0200 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? Message-ID: I want to register Python-callables with my VariableFloat-class (which is a subclass of a template-class Variable) 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 EventEmitterSync3 { public: void operator()() // Call the handler { if (_p_tau4eh) (*_p_tau4eh)( *this); }; void register_tau4ehS( void (*callable)( EventEmitterSync3& )) // Register the handler { _p_tau4eh = callable; }; private: void (*_p_tau4eh)( EventEmitterSync3& ) = NULL; // The handler }; The class VariableFloat (actually its base class _Variable) holds a member of type EventEmitterSync like so: private: EventEmitterSync3 _tau4ee_on_change; and the wrapper definitions are void (VariableFloat::*register_tau4ehS)( void (*)( EventEmitterSync3& )) = &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&))? /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate is: /usr/include/boost/python/converter/registered.hpp:77:3: note: template 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&)? 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 From brandsmeier at gmx.de Sat Oct 27 17:36:58 2012 From: brandsmeier at gmx.de (Holger Brandsmeier) Date: Sat, 27 Oct 2012 17:36:58 +0200 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? In-Reply-To: References: Message-ID: 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&. 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 wrote: > I want to register Python-callables with my VariableFloat-class (which is a > subclass of a template-class Variable) 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 EventEmitterSync3 > { > public: > > > > void operator()() // Call the handler > { > if (_p_tau4eh) > (*_p_tau4eh)( *this); > }; > > void register_tau4ehS( void (*callable)( > EventEmitterSync3& )) // Register the handler > { _p_tau4eh = callable; > }; > > > private: > void (*_p_tau4eh)( EventEmitterSync3& ) = > NULL; // The handler > }; > > > The class VariableFloat (actually its base class _Variable) holds a > member of type EventEmitterSync like so: > > private: > EventEmitterSync3 _tau4ee_on_change; > > and the wrapper definitions are > > void (VariableFloat::*register_tau4ehS)( void (*)( > EventEmitterSync3& )) = &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&))? > /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate is: > /usr/include/boost/python/converter/registered.hpp:77:3: note: > template 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&)? 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 From p.oseidon at datec.at Sat Oct 27 18:37:57 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Sat, 27 Oct 2012 18:37:57 +0200 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? References: Message-ID: 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&. 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 > wrote: >> I want to register Python-callables with my VariableFloat-class (which is >> a subclass of a template-class Variable) 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 EventEmitterSync3 >> { >> public: >> >> >> >> void operator()() // Call the handler >> { >> if (_p_tau4eh) >> (*_p_tau4eh)( *this); >> }; >> >> void register_tau4ehS( void (*callable)( >> EventEmitterSync3& )) // Register the handler >> { _p_tau4eh = callable; >> }; >> >> >> private: >> void (*_p_tau4eh)( EventEmitterSync3& ) >> = >> NULL; // The handler >> }; >> >> >> The class VariableFloat (actually its base class _Variable) holds a >> member of type EventEmitterSync like so: >> >> private: >> EventEmitterSync3 _tau4ee_on_change; >> >> and the wrapper definitions are >> >> void (VariableFloat::*register_tau4ehS)( void (*)( >> EventEmitterSync3& )) = &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&))? >> /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate >> is: /usr/include/boost/python/converter/registered.hpp:77:3: note: >> template 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&)? 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 From brandsmeier at gmx.de Sat Oct 27 19:14:44 2012 From: brandsmeier at gmx.de (Holger Brandsmeier) Date: Sat, 27 Oct 2012 19:14:44 +0200 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? In-Reply-To: References: Message-ID: 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 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&. 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 >> wrote: >>> I want to register Python-callables with my VariableFloat-class (which is >>> a subclass of a template-class Variable) 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 EventEmitterSync3 >>> { >>> public: >>> >>> >>> >>> void operator()() // Call the handler >>> { >>> if (_p_tau4eh) >>> (*_p_tau4eh)( *this); >>> }; >>> >>> void register_tau4ehS( void (*callable)( >>> EventEmitterSync3& )) // Register the handler >>> { _p_tau4eh = callable; >>> }; >>> >>> >>> private: >>> void (*_p_tau4eh)( EventEmitterSync3& ) >>> = >>> NULL; // The handler >>> }; >>> >>> >>> The class VariableFloat (actually its base class _Variable) holds a >>> member of type EventEmitterSync like so: >>> >>> private: >>> EventEmitterSync3 _tau4ee_on_change; >>> >>> and the wrapper definitions are >>> >>> void (VariableFloat::*register_tau4ehS)( void (*)( >>> EventEmitterSync3& )) = &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&))? >>> /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate >>> is: /usr/include/boost/python/converter/registered.hpp:77:3: note: >>> template 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&)? 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 From p.oseidon at datec.at Sat Oct 27 21:16:04 2012 From: p.oseidon at datec.at (Paul O. Seidon) Date: Sat, 27 Oct 2012 21:16:04 +0200 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? References: Message-ID: 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 > 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&. 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 >>> wrote: >>>> I want to register Python-callables with my VariableFloat-class (which >>>> is a subclass of a template-class Variable) 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 EventEmitterSync3 >>>> { >>>> public: >>>> >>>> >>>> >>>> void operator()() // Call the handler >>>> { >>>> if (_p_tau4eh) >>>> (*_p_tau4eh)( *this); >>>> }; >>>> >>>> void register_tau4ehS( void (*callable)( >>>> EventEmitterSync3& )) // Register the handler >>>> { _p_tau4eh = callable; >>>> }; >>>> >>>> >>>> private: >>>> void (*_p_tau4eh)( EventEmitterSync3& >>>> ) = >>>> NULL; // The handler >>>> }; >>>> >>>> >>>> The class VariableFloat (actually its base class _Variable) holds >>>> a member of type EventEmitterSync like so: >>>> >>>> private: >>>> EventEmitterSync3 _tau4ee_on_change; >>>> >>>> and the wrapper definitions are >>>> >>>> void (VariableFloat::*register_tau4ehS)( void (*)( >>>> EventEmitterSync3& )) = &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&))? >>>> /usr/include/boost/python/converter/registered.hpp:86:7: note: >>>> candidate is: /usr/include/boost/python/converter/registered.hpp:77:3: >>>> note: template 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&)? 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 From s_sourceforge at nedprod.com Sun Oct 28 02:16:56 2012 From: s_sourceforge at nedprod.com (Niall Douglas) Date: Sat, 27 Oct 2012 20:16:56 -0400 Subject: [C++-sig] [boost.python] Register a Python-callable with C++ code and call it from C++ code? In-Reply-To: References: , Message-ID: <508C7978.67.7C209079@s_sourceforge.nedprod.com> There should be no reason you can't wrap bound Boost/C++11 Functor instances and pass them in as callables to Python. You might need a little machinery to let BPL know what the function prototype is (assuming BPL doesn't already understand boost::function/std::function), but it ought to be straightforward. Try http://wiki.python.org/moin/boost.python/HowTo#boost.function_objects if it's still current. Also see http://stackoverflow.com/questions/3687279/registering-python-callable s-in-c-classes. To complete the circle, calling some python callable from C++, boost::python::call<>() is your friend. You just need to make your C++ callable by python (e.g. using the above), then call it as if it were any other kind of python callable. HTH, Niall On 27 Oct 2012 at 17:36, 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&. 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 wrote: > > I want to register Python-callables with my VariableFloat-class (which is a > > subclass of a template-class Variable) 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 EventEmitterSync3 > > { > > public: > > > > > > > > void operator()() // Call the handler > > { > > if (_p_tau4eh) > > (*_p_tau4eh)( *this); > > }; > > > > void register_tau4ehS( void (*callable)( > > EventEmitterSync3& )) // Register the handler > > { _p_tau4eh = callable; > > }; > > > > > > private: > > void (*_p_tau4eh)( EventEmitterSync3& ) = > > NULL; // The handler > > }; > > > > > > The class VariableFloat (actually its base class _Variable) holds a > > member of type EventEmitterSync like so: > > > > private: > > EventEmitterSync3 _tau4ee_on_change; > > > > and the wrapper definitions are > > > > void (VariableFloat::*register_tau4ehS)( void (*)( > > EventEmitterSync3& )) = &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&))? > > /usr/include/boost/python/converter/registered.hpp:86:7: note: candidate is: > > /usr/include/boost/python/converter/registered.hpp:77:3: note: > > template 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&)? 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 -- Any opinions or advice expressed here do NOT reflect those of my employer Research In Motion Inc. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/ -------------- next part -------------- A non-text attachment was scrubbed... Name: SMime.p7s Type: application/x-pkcs7-signature Size: 6061 bytes Desc: not available URL: From vanv0059 at umn.edu Tue Oct 30 14:39:37 2012 From: vanv0059 at umn.edu (Jeffrey Van Voorst) Date: Tue, 30 Oct 2012 08:39:37 -0500 Subject: [C++-sig] Boost.Python C++ exception translation question Message-ID: <508FD899.1060503@umn.edu> Greetings, I have used a method mentioned on stackoverflow (http://stackoverflow.com/questions/6908976/generalized-exception-translation-for-boost-python) for a generalized method to translate C++ exceptions to python exceptions. When debugging my code using gdb the frames seem to indicate that a C++ requires a call to all of the translation instances. Is this because of a Boost.Python implementation issue, my deriving all my python exceptions from PyExc_EnvironmentError (using PyErr_NewException), or possibly a misunderstanding I have about C++ and template function evaluations? My code for a generic approach is: template class GeneralizedTranslator{ public: GeneralizedTranslator(PyObject* py_exc): A_PyExc(py_exc) { bp::register_exception_translator(*this); } GeneralizedTranslator(const GeneralizedTranslator &other) : A_PyExc(other.A_PyExc) { ; } void operator()(const E &my_error) const { std::stringstream ostr; ostr << boost::diagnostic_information(my_error); PyErr_SetString(A_PyExc, ostr.str().c_str()); } private: PyObject *A_PyExc;}; // Allow for a simple translation declaration, remove scope problem template void translate_error(PyObject *E) { GeneralizedTranslator my_translator(E); } New exceptions are created by: PyObject *PyExc_Error_A = PyError_NewException("Exception_A", PyExc_EnvironmentError, NULL); The class is used as: BOOST_PYTHON_MODULE(_test) { // Here the exceptions (My_Exception_*) are derived from boost::exception and std::exception translate_error(PyExc_Error_A); translate_error(PyExc_Error_B); . . . } In gdb I see: . . . #52 0x00007fffeff04827 in boost::detail::function::function_obj_invoker2 >, boost::_bi::list3, boost::arg<2>, boost::_bi::value > > >, bool, boost::python::detail::exception_handler const&, boost::function0 const&>::invoke(boost::detail::function::function_buffer&, boost::python::detail::exception_handler const&, boost::function0 const&) () from /path/to/_test.so #53 0x00007ffff38a9ef4 in boost::python::detail::exception_handler::operator()(boost::function0 const&) const () from /path/to/libboost_python.so #54 0x00007fffeff04977 in boost::detail::function::function_obj_invoker2 >, boost::_bi::list3, boost::arg<2>, boost::_bi::value > > >, bool, boost::python::detail::exception_handler const&, boost::function0 const&>::invoke(boost::detail::function::function_buffer&, boost::python::detail::exception_handler c onst&, boost::function0 const&) () from /path/to/_test.so #55 0x00007ffff38a9cfa in boost::python::handle_exception_impl(boost::function0) () from /path/to/libboost_python.so #56 0x00007ffff38983e8 in ?? () from /path/to/libboost_python.so #57 0x000000000041ef47 in PyObject_Call () #58 0x00000000004a72b8 in PyEval_EvalFrameEx () #59 0x00000000004a95c1 in PyEval_EvalCodeEx () #60 0x00000000004a7752 in PyEval_EvalFrameEx () . . . Thanks, Jeff Van Voorst