Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap with boost-python a virtual class with a method returning a reference

I have two virtual classes I would like to wrap in boost python, I want to be able to write Python class that extends them. The thing is, one of the classes has a method that return a reference of the other class, and I can't figure how to do.

Here is a simplified version of code of class to be wrapped.

class Foo
{
    public:
    virtual ~Foo() {}
    virtual int a() = 0;
};

class Bar
{
    public:
    virtual ~Bar() {}
    virtual Foo const& b() = 0;
};

So I started wrapping about this way.

class FooWrap : public Foo, public wrapper<Foo>
{
    public:
    int a()
    {
        return this->get_override("a")();
    }
};

class BarWrap : public Bar, public wrapper<Bar>
{
    public:
    Foo const& b()
    {
        return this->get_override("b")();
    }
};

BOOST_PYTHON_MODULE(foobar)
{
    class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", pure_virtual(&Foo::a))
        ;
    class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", pure_virtual(&Bar::b))
        ;
}

And I get a compile error about "cannot instantiate abstract class [...] pure virtual function was not defined" "see declaration of 'foo::a'"

like image 617
MatthieuW Avatar asked Aug 07 '26 15:08

MatthieuW


2 Answers

I've been able to compile and run your code after I added call policy for Bar::b function:

BOOST_PYTHON_MODULE(foobar)
{
    class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", pure_virtual(&Foo::a));

    class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", pure_virtual(&Bar::b),
             return_internal_reference<>());
}

Basically, it's just means that lifetime of returned reference from Bar::b should be dependent on lifetime of Bar instance. You can read about call policies in boost docs.

What compiler and boost version are you using? I've got the following descriptive error with boost 1.46.0 and gcc 4.6.1:

error: no match for call to ‘(const boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<const Foo&>) (const Foo&)’
like image 104
alex vasi Avatar answered Aug 10 '26 11:08

alex vasi


The following code compiles for me. Inside your python Bar subclass you should be able to return a Foo instance from the b method.

#include <boost/python.hpp>

class Foo
{
public:
    virtual ~Foo() {}
    virtual int a() = 0;
};

class Bar
{
public:
    virtual ~Bar() {}
    virtual Foo const& b() = 0;
};


class FooWrap : public Foo, public boost::python::wrapper<Foo>
{
    public:
    int a()
    {
        return this->get_override("a")();
    }
};

class BarWrap : public Bar, public boost::python::wrapper<Bar>
{
    public:
    Foo const& b()
    {
        return this->get_override("b")();
    }
};

BOOST_PYTHON_MODULE(foobar)
{
    boost::python::class_<FooWrap, boost::noncopyable>("Foo")
        .def("a", boost::python::pure_virtual(&Foo::a)) ;

    boost::python::class_<BarWrap, boost::noncopyable>("Bar")
        .def("b", boost::python::pure_virtual(&Bar::b), boost::python::return_internal_reference<>());
}
like image 43
babak Avatar answered Aug 10 '26 13:08

babak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!