1

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)                                        \
                .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?

1 Answer 1

3

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> >())
Sign up to request clarification or add additional context in comments.

2 Comments

please, check the edit I have made to the post after your answer, the character limit didn't allow me to make such a comment here.
@sinad Unfortunately, looking further into the documentation, there doesn't seem to be an overload for def that accepts the result of an operator expression (here, self + self) and a policy, hence the result you are experiencing. Your approach is IMO very valid and I wouldn't hesitate to use the preprocessor to do some of the repetitive work for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.