0

Edit : making the constructor and destructor virtual didn't help

According to the boost/python documentation, I can expose a virtual function by having a wrapper around it. Here's their example copy-pasted here:

// base class
struct Base
{
    virtual ~Base() {}
    virtual int f() { return 0; }
};
// wrapper for the base function
struct BaseWrap : Base, wrapper<Base>
{
    int f()
    {
        if (override f = this->get_override("f"))
            return f(); // *note*
        return Base::f();
    }

    int default_f() { return this->Base::f(); }
};

// exposing the class
class_<BaseWrap, boost::noncopyable>("Base")
    .def("f", &Base::f, &BaseWrap::default_f);

Here's my cpp file with the minimal amount of code needed to replicate the error:

#include <iostream>
#include <python3.6m/Python.h>
#include <boost169/boost/python.hpp>
#include <boost169/boost/python/make_constructor.hpp>
#include <boost169/boost/python/detail/api_placeholder.hpp>
using namespace boost::python;
class BaseNode{
public:
    BaseNode(boost::python::object position);
    ~BaseNode();
    boost::python::object _position;
    virtual int test(){
        return 10;
    }
};

class BaseNodeVirtual:BaseNode, boost::python::wrapper<BaseNode>{
public:
    int test(){
        if (override test = this->get_override("test"))
            return test();
        return BaseNode::test();
    }
    int default_test(){
        return this->BaseNode::test();
    }
};

// pickle support for BaseNode
struct BaseNode_pickle_suite : boost::python::pickle_suite{
    static boost::python::tuple getinitargs(BaseNode const& baseNode){
        return boost::python::make_tuple(baseNode._position);
    }
    static boost::python::tuple getstate(boost::python::object obj)
    {
        BaseNode& baseNode = boost::python::extract<BaseNode&>(obj);
        return boost::python::make_tuple(obj.attr("__dict__"));
    }

    static void setstate(boost::python::object obj, boost::python::tuple state)
    {
        BaseNode& baseNode = boost::python::extract<BaseNode&>(obj);
        boost::python::dict d = extract<dict>(obj.attr("__dict__"));
        d.update(state[0]);

    }
    static bool getstate_manages_dict() { return true; }

};

BaseNode::BaseNode(boost::python::object position){
    this->_position = position;
}

BaseNode::~BaseNode(){

}


BOOST_PYTHON_MODULE(BaseNode){
    class_<BaseNodeVirtual, bases<BaseNode,boost::python::wrapper<BaseNode>>>("BaseNode", init<boost::python::object>())
    .def_readwrite("_position", &BaseNode::_position)
    .def_pickle(BaseNode_pickle_suite())
    .def("test", &BaseNode::test, &BaseNodeVirtual::default_test);
}

and it gives this long error that I don't quite understand.

/usr/include/boost169/boost/python/object/value_holder.hpp:133:13: note: candidates are:
minNode.cpp:17:7: note: BaseNodeVirtual::BaseNodeVirtual(const BaseNodeVirtual&)
 class BaseNodeVirtual: BaseNode, boost::python::wrapper<BaseNode>{
       ^
minNode.cpp:17:7: note:   no known conversion for argument 1 from ‘const boost::python::api::object’ to ‘const BaseNodeVirtual&’
minNode.cpp:17:7: note: BaseNodeVirtual::BaseNodeVirtual(BaseNodeVirtual&&)
minNode.cpp:17:7: note:   no known conversion for argument 1 from ‘const boost::python::api::object’ to ‘BaseNodeVirtual&&’
In file included from /usr/include/boost169/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:0,
                 from /usr/include/boost169/boost/python/object/value_holder.hpp:46,
                 from /usr/include/boost169/boost/python/object/class_metadata.hpp:14,
                 from /usr/include/boost169/boost/python/class.hpp:23,
                 from /usr/include/boost169/boost/python.hpp:18,
                 from minNode.cpp:3:
/usr/include/boost169/boost/python/object/value_holder.hpp:135:80: erreur: ‘boost::python::detail::wrapper_base’ is an inaccessible base of ‘BaseNodeVirtual’
     {
                                                                                ^
make: *** [minNode.o] Erreur 1

Initially I thought that this has something to do with the private inheritance (since according to this post and this post this is a problem that comes with protected and private inheritance), so I tried changing the inheritance to public instead, but it still gave me an error (with both base classes as public and not having boost::python::wrapper specified in bases):


/usr/include/boost169/boost/python/object/value_holder.hpp:133:13: erreur: no matching function for call to ‘BaseNodeVirtual::BaseNodeVirtual(boost::reference_wrapper<const BaseNode>::type&)’
             BOOST_PP_REPEAT_1ST(N, BOOST_PYTHON_UNFORWARD_LOCAL, nil)
             ^
/usr/include/boost169/boost/python/object/value_holder.hpp:133:13: note: candidates are:
minNode.cpp:17:7: note: BaseNodeVirtual::BaseNodeVirtual(const BaseNodeVirtual&)
 class BaseNodeVirtual:public BaseNode, public boost::python::wrapper<BaseNode>{
       ^
minNode.cpp:17:7: note:   no known conversion for argument 1 from ‘boost::reference_wrapper<const BaseNode>::type {aka const BaseNode}’ to ‘const BaseNodeVirtual&’
minNode.cpp:17:7: note: BaseNodeVirtual::BaseNodeVirtual(BaseNodeVirtual&&)
minNode.cpp:17:7: note:   no known conversion for argument 1 from ‘boost::reference_wrapper<const BaseNode>::type {aka const BaseNode}’ to ‘BaseNodeVirtual&&’
make: *** [minNode.o] Erreur 1

How can I fix this?

Thanks

qwerty_99
  • 640
  • 5
  • 20

1 Answers1

1

To match the example and build without any errors, you will need to change class to struct for the wrapper because Boost uses struct to layout memory. Also you will need to explicitly define your custom constructor in the wrapper. Lastly, change the line bases(...) to boost::noncopyable:

#include <iostream>
#include <python3.6m/Python.h>
#include <boost169/boost/python.hpp>
#include <boost169/boost/python/make_constructor.hpp>
#include <boost169/boost/python/detail/api_placeholder.hpp>
using namespace boost::python;
class BaseNode{
public:
    BaseNode(boost::python::object position);
    ~BaseNode();
    boost::python::object _position;
    virtual int test(){ return 10; }
};

BaseNode::BaseNode(boost::python::object position){
    this->_position = position;
}

BaseNode::~BaseNode(){

}

// pickle support for BaseNode
struct BaseNode_pickle_suite : boost::python::pickle_suite{
    static boost::python::tuple getinitargs(BaseNode const& baseNode){
        return boost::python::make_tuple(baseNode._position);
    }
    static boost::python::tuple getstate(boost::python::object obj)
    {
        BaseNode& baseNode = boost::python::extract<BaseNode&>(obj);
        return boost::python::make_tuple(obj.attr("__dict__"));
    }

    static void setstate(boost::python::object obj, boost::python::tuple state)
    {
        BaseNode& baseNode = boost::python::extract<BaseNode&>(obj);
        boost::python::dict d = extract<dict>(obj.attr("__dict__"));
        d.update(state[0]);

    }
    static bool getstate_manages_dict() { return true; }

};

struct BaseNodeVirtual : BaseNode, boost::python::wrapper<BaseNode> {
    BaseNodeVirtual(boost::python::object position) : BaseNode(position) {}
    int test(){
        if (override test = this->get_override("test"))
            return test();
        return BaseNode::test();
    }
    int default_test(){
        return this->BaseNode::test();
    }
};

int main() {

}

BOOST_PYTHON_MODULE(example){
    // exposing the class
    class_<BaseNodeVirtual, boost::noncopyable>("BaseNode", init<boost::python::object>())
        .def_readwrite("_position", &BaseNode::_position)
        .def_pickle(BaseNode_pickle_suite())
        .def("test", &BaseNode::test, &BaseNodeVirtual::default_test);

}
jackw11111
  • 1,457
  • 1
  • 17
  • 34