开发者

(boost.python) Error exposing overloaded operator+(). "TypeError: No to_python (by-value) converter found"

开发者 https://www.devze.com 2023-04-12 01:24 出处:网络
I\'m a newbie in boost.python and i\'m getting this error that I would like to get some help with. As a part of a larger project I\'m writing a wrapper for a vector class that I have. As you will noti

I'm a newbie in boost.python and i'm getting this error that I would like to get some help with. As a part of a larger project I'm writing a wrapper for a vector class that I have. As you will notice from the code bellow, this class can be 2D or 3D, but not a big difference for the current problem I'm having. I'm trying to wrap some operators defined in the vector class I have and this works fine as long as the function (or overloaded operator) do not return a "value" of type Vector, so I guess that python doesn't know what to do with the objects I'm returning by value. this is the code:

struct D2
{
   //...
   typedef Eigen::Matrix< long double, 2, 1 > Vector;
   //...
};
struct D3
{
   //...
   typedef Eigen::Matrix< long double, 3, 1 > Vector;
   //...
};

Now the following macro is defined to do the same job for the 2 possible dimensions

BOOST_PYTHON_MODULE(types)
{
using namespace boost::python;

#define GPS_PY_EXPOSE_VECTOR(DIM, NAME)                                                 \
        class_<DIM::Vector>(NAME)                                                       \
                .def(init<DIM::Vector>())                                               \
                .def("norm", &DIM::Vector::norm)                                        \
     开发者_JS百科           .def("__setitem__", &PyVectorHelper<DIM>::setVectorElem)                \
                .def("__getitem__", &PyVectorHelper<DIM>::getVectorElem)                \
                .def(self += self)                                                      \
                .def(self -= self)                                                      \
                .def(self + self)   /*Not working!!!*/                                  \
                .def(self - self)   /*Not working!!!*/                                  \
                .def("toStr", &PyVectorHelper<DIM>::toPyString)                         \
                .def("__str__", &PyVectorHelper<DIM>::toStdString)                      \
        ;

GPS_PY_EXPOSE_VECTOR(D2, "Vector2D")
GPS_PY_EXPOSE_VECTOR(D3, "Vector3D")
}

the above code works right, except when I try to use the "+" or "-" operator in python as follows:

>>>import types
>>>v1 = types.Vector2D()
>>>v2 = types.Vector2D()
>>>v3 = v1 + v2                //ERROR!!!

The error is the following:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: No to_python (by-value) converter found for C++ type: Eigen::CwiseBinaryOp<Eigen::internal::scalar_sum_op<long double>, Eigen::Matrix<long double, 2, 1, 0, 2, 1> const, Eigen::Matrix<long double, 2, 1, 0, 2, 1> const>

I followed the tutorial here, and I found no info related with the error on internet.

any help is very welcome! thanks in advance.

EDIT after Luc Danton's answer

To Luc Danton: thanks for your answer, I tried what you said but it doesn't work. this is the error I got:

error: no matching function for call to ‘boost::python::class_<Eigen::Matrix<long double, 2, 1, 0, 2, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::def(boost::python::detail::operator_<(boost::python::detail::operator_id)0u, boost::python::self_ns::self_t, boost::python::self_ns::self_t>, boost::python::return_value_policy<boost::python::to_python_value<Eigen::Matrix<long double, 2, 1, 0, 2, 1> >, boost::python::default_call_policies>)’

However, thanks to your comment, i got this idea: to write a helper function that performs the addition and convert the Eigen "expression object" (which is the private type representing the operator). This is:

template <typename TDim>
struct PyVectorHelper
{
    //...
    static typename TDim::Vector sum(typename TDim::Vector const &v1, typename TDim::Vector const &v2)
    {
        return v1 + v2;
    }
    //...
};

and then

.def("__add__", &PyVectorHelper<DIM>::sum)

this works fine and does as I want since PyVectorHelper<DIM>::sum returns a DIM::Vector. The problem is that almost every operator overloaded by Eigen returns an expression object, meaning that I would have to implement similar functions for almost all of them! that wouldn't be nice nor practical :P.

Maybe is still possible to use the return_value_policy and to_python_value so I can avoid this tedious operators rewriting?


It seems the matrix/vector library is using expression templates. In this case, and as you have remarked, operator+ is not returning a vector but a private type that represents the operation. The returned value is left trapped on the C++ side of things and can't be passed to Python as the private type is not registered.

Now I'm not too familiar with Boost.Python, but I think you can fix your problem with the return value policy. Passing a return_value_policy<to_python_value<DIM::Vector> > as policy would force converting the returned type to DIM::Vector, which you have registered. This would look like:

.def(self + self, return_value_policy<to_python_value<DIM::Vector> >())
0

精彩评论

暂无评论...
验证码 换一张
取 消