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 ?
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;
}