1

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 ?

wecx
  • 302
  • 2
  • 10
  • "This yield a cryptic compilation error (that I can't post here fully ..." - maybe try posting the start of it (which is likely to be the most relevant bit). – Jesper Juhl Oct 27 '19 at 16:33
  • @JesperJuhl ah actually it's not the ratio between number of code lines and text that matters but the amount of text itself. I've updated the question. – wecx Oct 27 '19 at 16:37
  • 1
    Possible duplicate of [Build problems when adding \`\_\_str\_\_\` method to Boost Python C++ class](https://stackoverflow.com/questions/2828903/build-problems-when-adding-str-method-to-boost-python-c-class) -- when I apply the suggestions in the answers, your code compiles. – Dan Mašek Oct 27 '19 at 20:12

1 Answers1

1

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;
}
Pato Sandaña
  • 519
  • 5
  • 14
PilouPili
  • 2,601
  • 2
  • 17
  • 31