2011-10-11 70 views
1

我在Boost.Python的一个新手,我得到这个错误,我希望得到一些帮助。作为一个更大项目的一部分,我正在为我有的矢量类写封装。正如你将会从代码中看到的那样,这个类可以是二维或三维的,但对于目前我遇到的问题并没有太大的区别。我试图总结在矢量类我已经定义了一些运营商,并且只要能正常工作的功能(或重载运算符)不返回类型为向量的“价值”,所以我想这蟒蛇不知道是什么与我按价值返回的对象做关系。这是代码:(boost.python)公开重载运算符+()的错误。 “类型错误:没有to_python(按值)转换器找到了”

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

现在下面的宏定义为2种可能的尺寸

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") 
} 

上面的代码工作的权利,做同样的工作,除了当我尝试使用“+ “或 ” - “ 运算符在Python如下:

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

误差如下:

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> 

我跟着教程here,我没有发现任何与互联网上的错误信息有关。

任何帮助是非常欢迎! 在此先感谢。吕克·丹东的回答

吕克丹东后

编辑:谢谢您的回答,我想你说的是什么,但它不工作。这是我得到的错误:

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>)’ 

然而,由于你的评论,我有这样的想法:编写执行另外一个辅助功能和转换征“表达的对象”(这是代表私营类型运营商)。这就是:

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

然后

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

这工作得很好,并不会因为我想要的,因为PyVectorHelper<DIM>::sum返回DIM::Vector。问题是几乎每个由Eigen重载的运算符都会返回一个表达式对象,这意味着我将不得不为几乎所有的实现类似的函数!这不会很好也不实际:P。

也许仍然可以使用return_value_policyto_python_value,这样我可以避免这种繁琐的操作符重写?

回答

3

看来基质/载体文库使用表达模板。在这种情况下,正如你所说的,operator+不是返回一个向量,而是一个表示操作的私有类型。返回的值留在事物的C++端,因为私有类型没有注册,所以无法传递给Python。

现在我不是太熟悉Boost.Python的,但我认为你可以用return value policy解决您的问题。作为政策传递return_value_policy<to_python_value<DIM::Vector> >将强制将返回的类型转换为您注册的DIM::Vector。这看起来像:

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

请检查编辑我已经发布到您的答案后,该字符的限制不允许我在这里做出这样的评论。 – sinad

+0

@sinad不幸的是,进一步查看文档,'def'接受运算符表达式的结果(这里是'self + self')和一个策略,似乎没有重载,因此您的结果经历。你的方法是IMO非常有效,我会毫不犹豫地使用预处理器为我做一些重复性的工作。 –