[C++-sig] A wrapped class contains another wrapped class. Hilarity ensues.

Roman Yakovenko roman.yakovenko at gmail.com
Tue Nov 27 08:50:26 CET 2007


On Nov 16, 2007 10:31 PM, Matthew Scouten <matthew.scouten at gmail.com> wrote:
> I have 2 c++ classes called foo and bar. I wrapped both. bar contains a foo as a public data member. foo contains a function called get_buffer that is exported as "__str__" and as the getter of the property 'buffer'
>
> if I construct a foo, I can call that function with no problem.
> if I create a bar and try to call the function on its foo I get an error.
>
> My C++ and B::P code:
>
> class foo
> {
> public:
>
>     foo() {std::strcpy(buffer, "good bye cruel world!\0\0");}
>     char buffer[24];
> };
>
> struct foo_wrapper : foo , wrapper<foo>
> {
>         foo_wrapper(const foo& f);
>         foo_wrapper();
>
>         //property getters
>         std::string get_buffer() const;
> };
>
> foo_wrapper::foo_wrapper(const foo& exch): foo(exch), wrapper<foo>(){}
>
> foo_wrapper::foo_wrapper(): foo(), wrapper<foo>(){}
>
> std::string foo_wrapper::get_buffer() const
> {
>     return std::string(foo::buffer);
> }
>
>
> class bar
> {
> public:
>     foo f;
> };
>
> class bar_wrapper: public bar, public wrapper<bar>
> {
> public:
>     bar_wrapper();
>     bar_wrapper(const bar &);
> };
>
> bar_wrapper::bar_wrapper() : bar(), wrapper<bar>(){}
>
> bar_wrapper::bar_wrapper(const bar &bb ) : bar(bb), wrapper<bar>(){}
>
> BOOST_PYTHON_MODULE(BusyBox)
> {
>
>     class_<foo_wrapper>("foo")
>         .def(init<>())
>         .add_property("buffer", &foo_wrapper::get_buffer)
>         .def("__str__", &foo_wrapper::get_buffer)
>         ;
>
>     class_<bar_wrapper>("bar")
>         .def_readwrite("f", &bar::f)
>         ;
> }
>
> A REPL session that demos the errors:>>> from BusyBox import *
> >>> f1 = foo()
> >>>
> >>> f1.buffer
> 'good bye cruel world!'
> >>> str(f1)
> 'good bye cruel world!'
> >>>
> >>> b1 = bar()
> >>>
> >>> b1.f.buffer #Generates error
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> Boost.Python.ArgumentError: Python argument types in
>     None.None(foo)
> did not match C++ signature:
>     None(struct foo_wrapper {lvalue})
> >>> str(b1.f)   #Generates error
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> Boost.Python.ArgumentError: Python argument types in
>     foo.__str__(foo)
> did not match C++ signature:
>     __str__(struct foo_wrapper {lvalue})
> >>>
> >>> f2 = b1.f
> >>>
> >>> b2.buffer   #Generates error
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> NameError: name 'b2' is not defined
> >>> str(f2)     #Generates error
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> Boost.Python.ArgumentError: Python argument types in
>     foo.__str__(foo)
> did not match C++ signature:
>     __str__(struct foo_wrapper {lvalue})
> >>>
>
> I feel like I must be doing something stupid. What is wrong?

You don't have, while the error messages contains enough information
it is really difficult to new user to understand what is going wrong.


> >>> str(f2)     #Generates error
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> Boost.Python.ArgumentError: Python argument types in
>     foo.__str__(foo)
> did not match C++ signature:
>     __str__(struct foo_wrapper {lvalue})
> >>>

The error message says that you cannot call foo.__str__ method with
"foo" as "this" pointer, but you should provide "foo_wrapper" for this
purpose. The library is right:

>struct foo_wrapper : foo , wrapper<foo>
> {
>        ...
>         std::string get_buffer() const;
> };

In order to call get_buffer, the object type should be "foo_wrapper",
not "foo". You didn't exposed "foo_wrapper" class, but "foo".
If you define get_buffer as


struct foo_wrapper : foo , wrapper<foo>
 {
        ...
         static std::string get_buffer(const foo& x ){ return
std::string(x.buffer); }
 };

Everything will work as expected.

The really confusing thing is that the library allowed you to call
__str__ method on object constructed from Python. This is because
internally it keeps foo_wrapper instance instead of "foo" one.

HTH

-- 
Roman Yakovenko
C++ Python language binding
http://www.language-binding.net/



More information about the Cplusplus-sig mailing list