Hi Nicodemus,
Yes, it follows the procedure in the tutorial about abstract virtual functions, ie, it only generates the virtual wrapper. You should still be able to override the abstract member functions in Python, though... is this the problem you're having?
No, that's not my problem. I want to be able to use pointers to abstract classes within python without wrapping all the derived classes (in fact, they are plugins), and, if possible, without writing a call_f function for every pure virtual method. I've played around with boost.python and found the solution below (Test.cpp). With pyste, i'd get an empty class Abstract. I wonder, if my solution is dangerous or even wrong ? Thanks in advance, Christoph /* Test.cpp */ struct Abstract { virtual void a() = 0; }; #include <boost/python.hpp> using namespace boost::python; BOOST_PYTHON_MODULE(myclasses) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) ; }
wiedeman@gmx.net writes:
Hi Nicodemus,
Yes, it follows the procedure in the tutorial about abstract virtual functions, ie, it only generates the virtual wrapper. You should still be able to override the abstract member functions in Python, though... is this the problem you're having?
No, that's not my problem. I want to be able to use pointers to abstract classes within python without wrapping all the derived classes (in fact, they are plugins), and, if possible, without writing a call_f function for every pure virtual method. I've played around with boost.python and found the solution below (Test.cpp). With pyste, i'd get an empty class Abstract. I wonder, if my solution is dangerous or even wrong ?
Thanks in advance, Christoph
/* Test.cpp */
struct Abstract { virtual void a() = 0; };
#include <boost/python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(myclasses) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") ^^^^^^^^^^^^ This part is wrong. .def("a", &Abstract::a) ; }
http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1748053 I'm not sure why people keep doing that; perhaps we need to fix the tutorial somehow? If you can, Christoph, it would be a big help if you could explain why you thought that was the right thing to do. Thanks, Dave -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hello Dave, sorry for the error in the posted code. This wasn't due to misunderstanding of the tutorial, but due to copy & paste. In fact, i got the code working with 'normal' boost.python, but wondered, why pyste doesn't provide a wrapper for the pure virtual function a(). Here is the code: struct Abstract { virtual void a() = 0; }; #include <boost/python.hpp> using namespace boost::python; BOOST_PYTHON_MODULE(wrap_Test) { class_<Abstract, boost::noncopyable>("Abstract", no_init) .def("a", &Abstract::a) ; } As far as i can tell, this code works fine, and Dave Abrahams suggested to do so in the thread he was pointing me on. Though the tutorial doesn't provide wrappers around pure virtual functions, the above code was quite obvious - but maybe it would be better to show how to wrap the pure virtual function f() of class Base. Christoph
Hi Nicodemus,
Yes, it follows the procedure in the tutorial about abstract virtual functions, ie, it only generates the virtual wrapper. You should still be able to override the abstract member functions in Python, though... is this the problem you're having?
No, that's not my problem. I want to be able to use pointers to abstract classes within python without wrapping all the derived classes (in fact, they are plugins), and, if possible, without writing a call_f function for every pure virtual method. I've played around with boost.python and found the solution below (Test.cpp). With pyste, i'd get an empty class Abstract. I wonder, if my solution is dangerous or even wrong ?
Thanks in advance, Christoph
/* Test.cpp */
struct Abstract { virtual void a() = 0; };
#include <boost/python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(myclasses) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") ^^^^^^^^^^^^ This part is wrong. .def("a", &Abstract::a) ; }
http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1748053
I'm not sure why people keep doing that; perhaps we need to fix the tutorial somehow? If you can, Christoph, it would be a big help if you could explain why you thought that was the right thing to do.
Thanks, Dave
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
Hello Dave, sorry for the error in the posted code. This wasn't due to misunderstanding of the tutorial, but due to copy & paste. In fact, i got the code working with 'normal' boost.python, but wondered, why pyste doesn't provide a wrapper for the pure virtual function a(). Here is the code: struct Abstract { virtual void a() = 0; }; #include <boost/python.hpp> using namespace boost::python; BOOST_PYTHON_MODULE(wrap_Test) { class_<Abstract, boost::noncopyable>("Abstract", no_init) .def("a", &Abstract::a) ; } As far as i can tell, this code works fine, and Dave Abrahams suggested to do so in the thread he was pointing me on. Though the tutorial doesn't provide wrappers around pure virtual functions, the above code was quite obvious - but maybe it would be better to show how to wrap the pure virtual function f() of class Base. Christoph
Hi Nicodemus,
Yes, it follows the procedure in the tutorial about abstract virtual functions, ie, it only generates the virtual wrapper. You should still be able to override the abstract member functions in Python, though... is this the problem you're having?
No, that's not my problem. I want to be able to use pointers to abstract classes within python without wrapping all the derived classes (in fact, they are plugins), and, if possible, without writing a call_f function for every pure virtual method. I've played around with boost.python and found the solution below (Test.cpp). With pyste, i'd get an empty class Abstract. I wonder, if my solution is dangerous or even wrong ?
Thanks in advance, Christoph
/* Test.cpp */
struct Abstract { virtual void a() = 0; };
#include <boost/python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(myclasses) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") ^^^^^^^^^^^^ This part is wrong. .def("a", &Abstract::a) ; }
http://aspn.activestate.com/ASPN/Mail/Message/c++-sig/1748053
I'm not sure why people keep doing that; perhaps we need to fix the tutorial somehow? If you can, Christoph, it would be a big help if you could explain why you thought that was the right thing to do.
Thanks, Dave
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
wiedeman@gmx.net wrote:
Hello Dave,
sorry for the error in the posted code. This wasn't due to misunderstanding of the tutorial, but due to copy & paste. In fact, i got the code working with 'normal' boost.python, but wondered, why pyste doesn't provide a wrapper for the pure virtual function a(). Here is the code:
struct Abstract { virtual void a() = 0; };
#include <boost/python.hpp> using namespace boost::python;
BOOST_PYTHON_MODULE(wrap_Test) { class_<Abstract, boost::noncopyable>("Abstract", no_init) .def("a", &Abstract::a) ; }
But this code won't work if the user wants to override a() in Python, right? We have two use cases regarding abstract classes, AFAIK: - The user doesn't want to override the abstract class in Python: it will use factory functions that create instances of derived classes. - The user wants to be able to override the methods of the abstract class in Python. Here is an attempt to support both: #include <boost/python.hpp> using namespace boost::python; struct Abstract { virtual void a() = 0; }; struct AbstractWrap: Abstract { AbstractWrap(PyObject* self_): self(self_) {} void a(){ call_method<void>(self, "a"); } PyObject* self; }; void call(Abstract* a) { a->a(); } BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) ; def("call", call); } It works, i.e., we can use instances of derived classes in C++ and we can override a() in Python, but it is not safe, because you can instantiate Abstract, and calling its a method will make Python crash. Adding no_init prevents the class from being instantiated, even in a derived class, so that does not work. There's a way to support both usages at the same time? Regards, Nicodemus.
#include <boost/python.hpp> using namespace boost::python;
struct Abstract { virtual void a() = 0; };
struct AbstractWrap: Abstract { AbstractWrap(PyObject* self_): self(self_) {} void a(){ call_method<void>(self, "a"); } PyObject* self; };
void call(Abstract* a) ^^^^^^^^^^^^^^^^^ let's say void call_a(...). Naming the method 'call' results in a Internal Compiler Error with gcc 2.95.2 and with gcc 3.2 :-) build/WrapTest.cpp: In function `void init_module_wrap_Test()': build/WrapTest.cpp:28: no matching function for call to `def(const char[5], <unknown type>)'
{ a->a(); }
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) ; def("call", call); }
It works, i.e., we can use instances of derived classes in C++ and we can override a() in Python, but it is not safe, because you can instantiate Abstract, and calling its a method will make Python crash. Adding no_init prevents the class from being instantiated, even in a derived class, so that does not work. There's a way to support both usages at the same time?
Now i see what's going wrong - an infinite recursion if the derived class doesn't implement a(). I suppose, that there is some way to check this, but cannot i'm not sure how to achieve it. Thanks for the clarification. Christoph
Nicodemus <nicodemus@globalite.com.br> writes:
It works, i.e., we can use instances of derived classes in C++ and we can override a() in Python, but it is not safe, because you can instantiate Abstract, and calling its a method will make Python crash. Adding no_init prevents the class from being instantiated, even in a derived class, so that does not work. There's a way to support both usages at the same time?
Not without changes to Boost.Python. We need a "default implementation" of a() which raises a Python exception or a version of call_method<> which refuses to call the method if it's actually in the same class... possibly also a smarter version of no_init would help, though I am sure it is not enough. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Nicodemus <nicodemus@globalite.com.br> writes:
It works, i.e., we can use instances of derived classes in C++ and we can override a() in Python, but it is not safe, because you can instantiate Abstract, and calling its a method will make Python crash. Adding no_init prevents the class from being instantiated, even in a derived class, so that does not work. There's a way to support both usages at the same time?
Not without changes to Boost.Python. We need a "default implementation" of a() which raises a Python exception or a version of call_method<> which refuses to call the method if it's actually in the same class... possibly also a smarter version of no_init would help, though I am sure it is not enough.
Ah, wait, try this: struct Abstract { virtual void a() = 0; }; struct AbstractWrap: Abstract { AbstractWrap(PyObject* self_): self(self_) {} void a(){ call_method<void>(self, "a"); } void default_a() { PyErr_SetString(PyExc_RuntimeError, "pure virtual called"); throw error_already_set(); } PyObject* self; }; void call(Abstract* a) { a->a(); } BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ; def("call", call); } I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice: BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ; def("call", call); } ?? -- Dave Abrahams Boost Consulting www.boost-consulting.com
At 20:54 2003-07-28, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ;
def("call", call); }
??
FWIW, we had a similar problem in luabind, where we needed to specify if a function was going to yield from a coroutine. We solved this by introducing a placeholder in the policy list, like this: .def("a", &Abstract::a, yield) This solution could also apply to this problem .def("a", &Abstract::a, pure_virtual) --- Daniel Wallin
Daniel Wallin <dalwan01@student.umu.se> writes:
At 20:54 2003-07-28, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ;
def("call", call); }
??
FWIW, we had a similar problem in luabind, where we needed to specify if a function was going to yield from a coroutine. We solved this by introducing a placeholder in the policy list, like this:
.def("a", &Abstract::a, yield)
This solution could also apply to this problem
.def("a", &Abstract::a, pure_virtual)
The deal here, though, is that I want to use the def_arg visitation trick to avoid expanding the def(...) interface (which is already way too big!) template <...> struct class_ { ... // Generic visitation template <class Derived> self& def(def_arg<Derived> const& visitor) { static_cast<Derived const&>(visitor).visit(*this); return *this; } ... }; -- Dave Abrahams Boost Consulting www.boost-consulting.com
At 21:42 2003-07-28, David Abrahams wrote:
Daniel Wallin <dalwan01@student.umu.se> writes:
At 20:54 2003-07-28, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ;
def("call", call); }
??
FWIW, we had a similar problem in luabind, where we needed to specify if a function was going to yield from a coroutine. We solved this by introducing a placeholder in the policy list, like this:
.def("a", &Abstract::a, yield)
This solution could also apply to this problem
.def("a", &Abstract::a, pure_virtual)
The deal here, though, is that I want to use the def_arg visitation trick to avoid expanding the def(...) interface (which is already way too big!)
template <...> struct class_ { ... // Generic visitation template <class Derived> self& def(def_arg<Derived> const& visitor) { static_cast<Derived const&>(visitor).visit(*this); return *this; } ... };
Ok, that's pretty cool. Our way doesn't expand the interface either though, since yield (or pure_virtual) is just a placeholder in the policy list. The implementation just does a search for yield in the policy list. But it's kind of nice with a non-intrusive approach too. --- Daniel Wallin
David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ;
def("call", call); }
??
Seems nice enough for me. 8)
Nicodemus <nicodemus@globalite.com.br> writes:
David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", &Abstract::a) .def("a", &AbstractWrap::default_a) ;
def("call", call); }
I just wish I knew a way to detect that a function was pure-virtual so we could have Boost.Python generate that default_a automatically.
Perhaps this interface would be nice:
BOOST_PYTHON_MODULE(test) { class_<Abstract, AbstractWrap, boost::noncopyable>("Abstract") .def("a", pure_virtual(&Abstract::a)) ;
def("call", call); }
??
Seems nice enough for me. 8)
OK, done; see <boost/python/pure_virtual.hpp>. Perhaps you should change Pyste to use this facility. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
OK, done; see <boost/python/pure_virtual.hpp>. Perhaps you should change Pyste to use this facility.
I did, but I am getting this compiler error: pure.cpp d:/programming/libraries/boost-cvs/boost/boost/python/detail/nullary_function_ad aptor.hpp(33): catastrophic error: expected a file name # include BOOST_PP_LOCAL_ITERATE() ^ Perhaps I am missing something? Here is the code: // Includes ==================================================================== #include <pure.h> #include <boost/python/pure_virtual.hpp> #include <boost/python.hpp> // Using ======================================================================= using namespace boost::python; // Declarations ================================================================ namespace { struct A_Wrapper: A { A_Wrapper(PyObject* self_, const A& p0): A(p0), self(self_) {} A_Wrapper(PyObject* self_): A(), self(self_) {} void foo() { call_method< void >(self, "foo"); } PyObject* self; }; }// namespace // Module ====================================================================== BOOST_PYTHON_MODULE(pure) { class_< A, boost::noncopyable, A_Wrapper >("A", init< >()) .def("foo", pure_virtual(&A::foo), &A_Wrapper::default_foo) ; }
Nicodemus <nicodemus@globalite.com.br> writes:
David Abrahams wrote:
OK, done; see <boost/python/pure_virtual.hpp>. Perhaps you should change Pyste to use this facility.
I did, but I am getting this compiler error:
pure.cpp d:/programming/libraries/boost-cvs/boost/boost/python/detail/nullary_function_ad aptor.hpp(33): catastrophic error: expected a file name # include BOOST_PP_LOCAL_ITERATE() ^
Perhaps I am missing something? Here is the code:
I just checked in some missing #includes. Please try again. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Nicodemus <nicodemus@globalite.com.br> writes:
David Abrahams wrote:
OK, done; see <boost/python/pure_virtual.hpp>. Perhaps you should change Pyste to use this facility.
I did, but I am getting this compiler error:
pure.cpp d:/programming/libraries/boost-cvs/boost/boost/python/detail/nullary_function_ad aptor.hpp(33): catastrophic error: expected a file name # include BOOST_PP_LOCAL_ITERATE() ^
Perhaps I am missing something? Here is the code:
I just checked in some missing #includes. Please try again.
Thanks for the quick fix! I am still getting errors thought: pure.cpp d:/programming/libraries/boost-cvs/boost/boost/preprocessor/iteration/detail/rlo cal.hpp(779): error: identifier "BOOST_PP_ENUM_BINARY_PARAMS_Z" is undefined BOOST_PP_LOCAL_MACRO(1) ^ d:/programming/libraries/boost-cvs/boost/boost/preprocessor/iteration/detail/rlo cal.hpp(779): error: expected a ")" BOOST_PP_LOCAL_MACRO(1) ^ d:/programming/libraries/boost-cvs/boost/boost/preprocessor/iteration/detail/rlo cal.hpp(779): error: expected a type specifier BOOST_PP_LOCAL_MACRO(1) ^ d:/programming/libraries/boost-cvs/boost/boost/preprocessor/iteration/detail/rlo cal.hpp(779): error: parameter of abstract class type "A" is not allowed: function "A::foo" is a pure virtual function BOOST_PP_LOCAL_MACRO(1) ^ d:/programming/libraries/boost-cvs/boost/boost/preprocessor/iteration/detail/rlo cal.hpp(779): error: expected a ";" BOOST_PP_LOCAL_MACRO(1) ^ <more errors follow, but I don't think they're revelant> Also, shouldn't <boost/python/pure_virtual.hpp> be included by <booost/python.hpp>? Thanks, Nicodemus.
Nicodemus <nicodemus@globalite.com.br> writes:
Thanks for the quick fix!
I am still getting errors thought:
<snip>
Also, shouldn't <boost/python/pure_virtual.hpp> be included by <booost/python.hpp>?
<sigh>Please try again, again. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Nicodemus <nicodemus@globalite.com.br> writes:
Thanks for the quick fix!
I am still getting errors thought:
<snip>
Also, shouldn't <boost/python/pure_virtual.hpp> be included by <booost/python.hpp>?
<sigh>Please try again, again.
Working just fine, thanks! I am about to commit the necessary changes to make Pyste use this facility. Regards, Nicodemus.
participants (4)
-
Daniel Wallin -
David Abrahams -
Nicodemus -
wiedeman@gmx.net