Search code examples
pythonc++boost-python

Cannot interface __str__ special method with Boost::Python


I am trying to link some C++ code to the __str__ special method of a Python object using Boost::Python.

#include <boost/python.hpp>
#include <iostream>

using namespace std;

struct POINT
{
    int x,y;
    POINT(int x, int y) : x(x), y(y) {}          
};

ostream & operator<<(ostream & os, POINT p)
{
    os << "(x:" << p.x << ", y:" << p.y << ")";
    return os;
}

using namespace boost::python;

BOOST_PYTHON_MODULE(wrapper)
{
    class_<POINT>("point", init<int,int>())
        .def(str(self));
}

which is inspired by the official doc. This yields a cryptic compilation error:

    In file included from /usr/include/boost/python/object_core.hpp:20,
                 from /usr/include/boost/python/args.hpp:22,
                 from /usr/include/boost/python.hpp:11,
                 from wrapper.cpp:1:
/usr/include/boost/python/def_visitor.hpp: In instantiation of ‘static void boost::python::def_visitor_access::visit(const V&, classT&) [with V = boost::python::def_visitor<boost::python::api::object>; classT = boost::python::class_<POINT>]’:
/usr/include/boost/python/def_visitor.hpp:67:34:   required from ‘void boost::python::def_visitor<DerivedVisitor>::visit(classT&) const [with classT = boost::python::class_<POINT>; DerivedVisitor = boost::python::api::object]’
/usr/include/boost/python/class.hpp:221:9:   required from ‘boost::python::class_<T, X1, X2, X3>::self& boost::python::class_<T, X1, X2, X3>::def(const boost::python::def_visitor<Derived>&) [with Derived = boost::python::api::object; W = POINT; X1 = boost::python::detail::not_specified; X2 = boost::python::detail::not_specified; X3 = boost::python::detail::not_specified; boost::python::class_<T, X1, X2, X3>::self = boost::python::class_<POINT>]’
wrapper.cpp:49:20:   required from here
/usr/include/boost/python/def_visitor.hpp:31:9: error: no matching function for call to ‘boost::python::api::object::visit(boost::python::class_<POINT>&) const’
         v.derived_visitor().visit(c);
         ^
In file included from /usr/include/boost/python/args.hpp:22,
                 from /usr/include/boost/python.hpp:11,
                 from wrapper.cpp:1:
/usr/include/boost/python/object_core.hpp:160:12: note: candidate: ‘template<class ClassT, class DocStringT> void boost::python::api::object_operators<U>::visit(ClassT&, const char*, const boost::python::detail::def_helper<DocStringT>&) const [with ClassT = ClassT; DocStringT = DocStringT; U = boost::python::api::object]’
       void visit(ClassT& cl, char const* name, python::detail::def_helper<DocStringT> const& helper) const
            ^~~~~
/usr/include/boost/python/object_core.hpp:160:12: note:   template argument deduction/substitution failed:
In file included from /usr/include/boost/python/object_core.hpp:20,
                 from /usr/include/boost/python/args.hpp:22,
                 from /usr/include/boost/python.hpp:11,
                 from wrapper.cpp:1:
/usr/include/boost/python/def_visitor.hpp:31:9: note:   candidate expects 3 arguments, 1 provided
         v.derived_visitor().visit(c);

Can a soul more enlightened than mine point me what I'm missing ?


Solution

  • self needs to be defined in self_ns namespace

    BOOST_PYTHON_MODULE(wrapper)
    {
        class_<POINT>("point", init<int, int>())
            .def(self_ns::str(self_ns::self));
    }
    

    Non related: prefer to use a const reference instead of a copy of the object to the stream operator. Otherwise you are creating unnecessary copies of your objects.

    ostream& operator<<(ostream& os, const POINT& p)
    {
        os << "(x:" << p.x << ", y:" << p.y << ")";
        return os;
    }